From 2c10d571169abab9181e0c91b259e0c4e392bc5b Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Thu, 20 Dec 2012 21:24:07 +0100 Subject: [PATCH 001/101] drm/i915: wake up all pageflip waiters Otherwise it seems like we can get stuck with concurrent waiters. Right now this /shouldn't/ be a problem, since all pending pageflip waiters are serialized by the one mode_config.mutex, so there's at most on waiter. But better paranoid than sorry, since this is tricky code. v2: WARN_ON(waitqueue_active) before waiting, as suggested by Chris Wilson. Acked-by: Chris Wilson Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_display.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 8c36a11a9a57..40b6b5e9d6ef 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -2220,6 +2220,8 @@ intel_finish_fb(struct drm_framebuffer *old_fb) bool was_interruptible = dev_priv->mm.interruptible; int ret; + WARN_ON(waitqueue_active(&dev_priv->pending_flip_queue)); + wait_event(dev_priv->pending_flip_queue, atomic_read(&dev_priv->mm.wedged) || atomic_read(&obj->pending_flip) == 0); @@ -2887,6 +2889,8 @@ static void intel_crtc_wait_for_pending_flips(struct drm_crtc *crtc) if (crtc->fb == NULL) return; + WARN_ON(waitqueue_active(&dev_priv->pending_flip_queue)); + wait_event(dev_priv->pending_flip_queue, !intel_crtc_has_pending_flip(crtc)); @@ -6824,7 +6828,7 @@ static void do_intel_finish_page_flip(struct drm_device *dev, obj = work->old_fb_obj; - wake_up(&dev_priv->pending_flip_queue); + wake_up_all(&dev_priv->pending_flip_queue); queue_work(dev_priv->wq, &work->work); From af5163acd8319dbc901bb59a8d503d8bb774d88b Mon Sep 17 00:00:00 2001 From: Egbert Eich Date: Thu, 10 Jan 2013 10:02:39 -0500 Subject: [PATCH 002/101] drm/i915: Remove pch_rq_mask from struct drm_i915_private. This variable is only used locally in the irq postinstall functions for ivybridge and ironlake. Signed-off-by: Egbert Eich Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_drv.h | 1 - drivers/gpu/drm/i915/i915_irq.c | 10 ++++++---- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index b1b1b7350ca4..910cc0b545a6 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -697,7 +697,6 @@ typedef struct drm_i915_private { u32 pipestat[2]; u32 irq_mask; u32 gt_irq_mask; - u32 pch_irq_mask; u32 hotplug_supported_mask; struct work_struct hotplug_work; diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c index 6689a61b02a3..202813128441 100644 --- a/drivers/gpu/drm/i915/i915_irq.c +++ b/drivers/gpu/drm/i915/i915_irq.c @@ -1892,6 +1892,7 @@ static int ironlake_irq_postinstall(struct drm_device *dev) DE_AUX_CHANNEL_A; u32 render_irqs; u32 hotplug_mask; + u32 pch_irq_mask; dev_priv->irq_mask = ~display_mask; @@ -1935,10 +1936,10 @@ static int ironlake_irq_postinstall(struct drm_device *dev) SDE_AUX_MASK); } - dev_priv->pch_irq_mask = ~hotplug_mask; + pch_irq_mask = ~hotplug_mask; I915_WRITE(SDEIIR, I915_READ(SDEIIR)); - I915_WRITE(SDEIMR, dev_priv->pch_irq_mask); + I915_WRITE(SDEIMR, pch_irq_mask); I915_WRITE(SDEIER, hotplug_mask); POSTING_READ(SDEIER); @@ -1966,6 +1967,7 @@ static int ivybridge_irq_postinstall(struct drm_device *dev) DE_AUX_CHANNEL_A_IVB; u32 render_irqs; u32 hotplug_mask; + u32 pch_irq_mask; dev_priv->irq_mask = ~display_mask; @@ -1995,10 +1997,10 @@ static int ivybridge_irq_postinstall(struct drm_device *dev) SDE_PORTD_HOTPLUG_CPT | SDE_GMBUS_CPT | SDE_AUX_MASK_CPT); - dev_priv->pch_irq_mask = ~hotplug_mask; + pch_irq_mask = ~hotplug_mask; I915_WRITE(SDEIIR, I915_READ(SDEIIR)); - I915_WRITE(SDEIMR, dev_priv->pch_irq_mask); + I915_WRITE(SDEIMR, pch_irq_mask); I915_WRITE(SDEIER, hotplug_mask); POSTING_READ(SDEIER); From d865110cc2345d67752cd7e1350b391c34feb2aa Mon Sep 17 00:00:00 2001 From: Imre Deak Date: Mon, 7 Jan 2013 21:47:33 +0200 Subject: [PATCH 003/101] drm/i915: merge get_gtt_alignment/get_unfenced_gtt_alignment() The two functions are rather similar, so merge them. Signed-off-by: Imre Deak Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_drv.h | 5 ++- drivers/gpu/drm/i915/i915_gem.c | 44 ++++---------------------- drivers/gpu/drm/i915/i915_gem_tiling.c | 6 ++-- 3 files changed, 12 insertions(+), 43 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 910cc0b545a6..0b09361d37ae 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -1565,9 +1565,8 @@ void i915_gem_free_all_phys_object(struct drm_device *dev); void i915_gem_release(struct drm_device *dev, struct drm_file *file); uint32_t -i915_gem_get_unfenced_gtt_alignment(struct drm_device *dev, - uint32_t size, - int tiling_mode); +i915_gem_get_gtt_alignment(struct drm_device *dev, uint32_t size, + int tiling_mode, bool fenced); int i915_gem_object_set_cache_level(struct drm_i915_gem_object *obj, enum i915_cache_level cache_level); diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index e6cc020ea32c..2166b61053c6 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -1463,16 +1463,15 @@ i915_gem_get_gtt_size(struct drm_device *dev, uint32_t size, int tiling_mode) * Return the required GTT alignment for an object, taking into account * potential fence register mapping. */ -static uint32_t -i915_gem_get_gtt_alignment(struct drm_device *dev, - uint32_t size, - int tiling_mode) +uint32_t +i915_gem_get_gtt_alignment(struct drm_device *dev, uint32_t size, + int tiling_mode, bool fenced) { /* * Minimum alignment is 4k (GTT page size), but might be greater * if a fence register is needed for the object. */ - if (INTEL_INFO(dev)->gen >= 4 || + if (INTEL_INFO(dev)->gen >= 4 || (!fenced && IS_G33(dev)) || tiling_mode == I915_TILING_NONE) return 4096; @@ -1483,35 +1482,6 @@ i915_gem_get_gtt_alignment(struct drm_device *dev, return i915_gem_get_gtt_size(dev, size, tiling_mode); } -/** - * i915_gem_get_unfenced_gtt_alignment - return required GTT alignment for an - * unfenced object - * @dev: the device - * @size: size of the object - * @tiling_mode: tiling mode of the object - * - * Return the required GTT alignment for an object, only taking into account - * unfenced tiled surface requirements. - */ -uint32_t -i915_gem_get_unfenced_gtt_alignment(struct drm_device *dev, - uint32_t size, - int tiling_mode) -{ - /* - * Minimum alignment is 4k (GTT page size) for sane hw. - */ - if (INTEL_INFO(dev)->gen >= 4 || IS_G33(dev) || - tiling_mode == I915_TILING_NONE) - return 4096; - - /* Previous hardware however needs to be aligned to a power-of-two - * tile height. The simplest method for determining this is to reuse - * the power-of-tile object size. - */ - return i915_gem_get_gtt_size(dev, size, tiling_mode); -} - static int i915_gem_object_create_mmap_offset(struct drm_i915_gem_object *obj) { struct drm_i915_private *dev_priv = obj->base.dev->dev_private; @@ -2934,11 +2904,11 @@ i915_gem_object_bind_to_gtt(struct drm_i915_gem_object *obj, obj->tiling_mode); fence_alignment = i915_gem_get_gtt_alignment(dev, obj->base.size, - obj->tiling_mode); + obj->tiling_mode, true); unfenced_alignment = - i915_gem_get_unfenced_gtt_alignment(dev, + i915_gem_get_gtt_alignment(dev, obj->base.size, - obj->tiling_mode); + obj->tiling_mode, false); if (alignment == 0) alignment = map_and_fenceable ? fence_alignment : diff --git a/drivers/gpu/drm/i915/i915_gem_tiling.c b/drivers/gpu/drm/i915/i915_gem_tiling.c index 65f1d4f3f775..cb71ded7122e 100644 --- a/drivers/gpu/drm/i915/i915_gem_tiling.c +++ b/drivers/gpu/drm/i915/i915_gem_tiling.c @@ -374,9 +374,9 @@ i915_gem_set_tiling(struct drm_device *dev, void *data, /* Rebind if we need a change of alignment */ if (!obj->map_and_fenceable) { u32 unfenced_alignment = - i915_gem_get_unfenced_gtt_alignment(dev, - obj->base.size, - args->tiling_mode); + i915_gem_get_gtt_alignment(dev, obj->base.size, + args->tiling_mode, + false); if (obj->gtt_offset & (unfenced_alignment - 1)) ret = i915_gem_object_unbind(obj); } From 56c844e539f1f6f5768c5f73f119e6f4aed9d320 Mon Sep 17 00:00:00 2001 From: Imre Deak Date: Mon, 7 Jan 2013 21:47:34 +0200 Subject: [PATCH 004/101] drm/i915: merge {i965, sandybridge}_write_fence_reg() The two functions are rather similar, so merge them. Signed-off-by: Imre Deak Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_gem.c | 44 +++++++++++---------------------- 1 file changed, 15 insertions(+), 29 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index 2166b61053c6..718574eb66de 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -2507,52 +2507,38 @@ int i915_gpu_idle(struct drm_device *dev) return 0; } -static void sandybridge_write_fence_reg(struct drm_device *dev, int reg, - struct drm_i915_gem_object *obj) -{ - drm_i915_private_t *dev_priv = dev->dev_private; - uint64_t val; - - if (obj) { - u32 size = obj->gtt_space->size; - - val = (uint64_t)((obj->gtt_offset + size - 4096) & - 0xfffff000) << 32; - val |= obj->gtt_offset & 0xfffff000; - val |= (uint64_t)((obj->stride / 128) - 1) << - SANDYBRIDGE_FENCE_PITCH_SHIFT; - - if (obj->tiling_mode == I915_TILING_Y) - val |= 1 << I965_FENCE_TILING_Y_SHIFT; - val |= I965_FENCE_REG_VALID; - } else - val = 0; - - I915_WRITE64(FENCE_REG_SANDYBRIDGE_0 + reg * 8, val); - POSTING_READ(FENCE_REG_SANDYBRIDGE_0 + reg * 8); -} - static void i965_write_fence_reg(struct drm_device *dev, int reg, struct drm_i915_gem_object *obj) { drm_i915_private_t *dev_priv = dev->dev_private; + int fence_reg; + int fence_pitch_shift; uint64_t val; + if (INTEL_INFO(dev)->gen >= 6) { + fence_reg = FENCE_REG_SANDYBRIDGE_0; + fence_pitch_shift = SANDYBRIDGE_FENCE_PITCH_SHIFT; + } else { + fence_reg = FENCE_REG_965_0; + fence_pitch_shift = I965_FENCE_PITCH_SHIFT; + } + if (obj) { u32 size = obj->gtt_space->size; val = (uint64_t)((obj->gtt_offset + size - 4096) & 0xfffff000) << 32; val |= obj->gtt_offset & 0xfffff000; - val |= ((obj->stride / 128) - 1) << I965_FENCE_PITCH_SHIFT; + val |= (uint64_t)((obj->stride / 128) - 1) << fence_pitch_shift; if (obj->tiling_mode == I915_TILING_Y) val |= 1 << I965_FENCE_TILING_Y_SHIFT; val |= I965_FENCE_REG_VALID; } else val = 0; - I915_WRITE64(FENCE_REG_965_0 + reg * 8, val); - POSTING_READ(FENCE_REG_965_0 + reg * 8); + fence_reg += reg * 8; + I915_WRITE64(fence_reg, val); + POSTING_READ(fence_reg); } static void i915_write_fence_reg(struct drm_device *dev, int reg, @@ -2636,7 +2622,7 @@ static void i915_gem_write_fence(struct drm_device *dev, int reg, { switch (INTEL_INFO(dev)->gen) { case 7: - case 6: sandybridge_write_fence_reg(dev, reg, obj); break; + case 6: case 5: case 4: i965_write_fence_reg(dev, reg, obj); break; case 3: i915_write_fence_reg(dev, reg, obj); break; From 0fa877965194fa79fe87944844185d90cfc35352 Mon Sep 17 00:00:00 2001 From: Imre Deak Date: Mon, 7 Jan 2013 21:47:35 +0200 Subject: [PATCH 005/101] drm/i915: use gtt_get_size() instead of open coding it Signed-off-by: Imre Deak Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_drv.h | 2 ++ drivers/gpu/drm/i915/i915_gem.c | 2 +- drivers/gpu/drm/i915/i915_gem_tiling.c | 13 +------------ 3 files changed, 4 insertions(+), 13 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 0b09361d37ae..35ecabc711ed 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -1564,6 +1564,8 @@ void i915_gem_detach_phys_object(struct drm_device *dev, void i915_gem_free_all_phys_object(struct drm_device *dev); void i915_gem_release(struct drm_device *dev, struct drm_file *file); +uint32_t +i915_gem_get_gtt_size(struct drm_device *dev, uint32_t size, int tiling_mode); uint32_t i915_gem_get_gtt_alignment(struct drm_device *dev, uint32_t size, int tiling_mode, bool fenced); diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index 718574eb66de..313bdbaba3cd 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -1435,7 +1435,7 @@ i915_gem_release_mmap(struct drm_i915_gem_object *obj) obj->fault_mappable = false; } -static uint32_t +uint32_t i915_gem_get_gtt_size(struct drm_device *dev, uint32_t size, int tiling_mode) { uint32_t gtt_size; diff --git a/drivers/gpu/drm/i915/i915_gem_tiling.c b/drivers/gpu/drm/i915/i915_gem_tiling.c index cb71ded7122e..e76f0d8470a1 100644 --- a/drivers/gpu/drm/i915/i915_gem_tiling.c +++ b/drivers/gpu/drm/i915/i915_gem_tiling.c @@ -272,18 +272,7 @@ i915_gem_object_fence_ok(struct drm_i915_gem_object *obj, int tiling_mode) return false; } - /* - * Previous chips need to be aligned to the size of the smallest - * fence register that can contain the object. - */ - if (INTEL_INFO(obj->base.dev)->gen == 3) - size = 1024*1024; - else - size = 512*1024; - - while (size < obj->base.size) - size <<= 1; - + size = i915_gem_get_gtt_size(obj->base.dev, obj->base.size, tiling_mode); if (obj->gtt_space->size != size) return false; From dd624afd533bdc87b8c10835515a0c8b2b9868b1 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Tue, 15 Jan 2013 12:39:35 +0000 Subject: [PATCH 006/101] drm/i915: Add a debug interface to forcibly evict and shrink our object caches As a means to investigate some bad system behaviour related to the purging of the active, inactive and unbound lists, it is useful to be able to manually control when those lists should be cleared. v2: use _safe list iterators as we kick objects from the list as we walk. Signed-off-by: Chris Wilson [danvet: Add a small comment explaining why we don't need to check and wait for gpu resets, acked by Chris on irc.] Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_debugfs.c | 104 ++++++++++++++++++++++++++++ drivers/gpu/drm/i915/i915_drv.h | 1 + drivers/gpu/drm/i915/i915_gem.c | 2 +- 3 files changed, 106 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/i915_debugfs.c b/drivers/gpu/drm/i915/i915_debugfs.c index f7d88e99ebf0..f94418bd1ed2 100644 --- a/drivers/gpu/drm/i915/i915_debugfs.c +++ b/drivers/gpu/drm/i915/i915_debugfs.c @@ -1776,6 +1776,102 @@ static const struct file_operations i915_ring_stop_fops = { .llseek = default_llseek, }; +#define DROP_UNBOUND 0x1 +#define DROP_BOUND 0x2 +#define DROP_RETIRE 0x4 +#define DROP_ACTIVE 0x8 +#define DROP_ALL (DROP_UNBOUND | \ + DROP_BOUND | \ + DROP_RETIRE | \ + DROP_ACTIVE) +static ssize_t +i915_drop_caches_read(struct file *filp, + char __user *ubuf, + size_t max, + loff_t *ppos) +{ + char buf[20]; + int len; + + len = snprintf(buf, sizeof(buf), "0x%08x\n", DROP_ALL); + if (len > sizeof(buf)) + len = sizeof(buf); + + return simple_read_from_buffer(ubuf, max, ppos, buf, len); +} + +static ssize_t +i915_drop_caches_write(struct file *filp, + const char __user *ubuf, + size_t cnt, + loff_t *ppos) +{ + struct drm_device *dev = filp->private_data; + struct drm_i915_private *dev_priv = dev->dev_private; + struct drm_i915_gem_object *obj, *next; + char buf[20]; + int val = 0, ret; + + if (cnt > 0) { + if (cnt > sizeof(buf) - 1) + return -EINVAL; + + if (copy_from_user(buf, ubuf, cnt)) + return -EFAULT; + buf[cnt] = 0; + + val = simple_strtoul(buf, NULL, 0); + } + + DRM_DEBUG_DRIVER("Dropping caches: 0x%08x\n", val); + + /* No need to check and wait for gpu resets, only libdrm auto-restarts + * on ioctls on -EAGAIN. */ + ret = mutex_lock_interruptible(&dev->struct_mutex); + if (ret) + return ret; + + if (val & DROP_ACTIVE) { + ret = i915_gpu_idle(dev); + if (ret) + goto unlock; + } + + if (val & (DROP_RETIRE | DROP_ACTIVE)) + i915_gem_retire_requests(dev); + + if (val & DROP_BOUND) { + list_for_each_entry_safe(obj, next, &dev_priv->mm.inactive_list, mm_list) + if (obj->pin_count == 0) { + ret = i915_gem_object_unbind(obj); + if (ret) + goto unlock; + } + } + + if (val & DROP_UNBOUND) { + list_for_each_entry_safe(obj, next, &dev_priv->mm.unbound_list, gtt_list) + if (obj->pages_pin_count == 0) { + ret = i915_gem_object_put_pages(obj); + if (ret) + goto unlock; + } + } + +unlock: + mutex_unlock(&dev->struct_mutex); + + return ret ?: cnt; +} + +static const struct file_operations i915_drop_caches_fops = { + .owner = THIS_MODULE, + .open = simple_open, + .read = i915_drop_caches_read, + .write = i915_drop_caches_write, + .llseek = default_llseek, +}; + static ssize_t i915_max_freq_read(struct file *filp, char __user *ubuf, @@ -2172,6 +2268,12 @@ int i915_debugfs_init(struct drm_minor *minor) if (ret) return ret; + ret = i915_debugfs_create(minor->debugfs_root, minor, + "i915_gem_drop_caches", + &i915_drop_caches_fops); + if (ret) + return ret; + ret = i915_debugfs_create(minor->debugfs_root, minor, "i915_error_state", &i915_error_state_fops); @@ -2203,6 +2305,8 @@ void i915_debugfs_cleanup(struct drm_minor *minor) 1, minor); drm_debugfs_remove_files((struct drm_info_list *) &i915_cache_sharing_fops, 1, minor); + drm_debugfs_remove_files((struct drm_info_list *) &i915_drop_caches_fops, + 1, minor); drm_debugfs_remove_files((struct drm_info_list *) &i915_ring_stop_fops, 1, minor); drm_debugfs_remove_files((struct drm_info_list *) &i915_error_state_fops, diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 35ecabc711ed..8f5b2816fc03 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -1445,6 +1445,7 @@ int __must_check i915_gem_object_pin(struct drm_i915_gem_object *obj, bool nonblocking); void i915_gem_object_unpin(struct drm_i915_gem_object *obj); int __must_check i915_gem_object_unbind(struct drm_i915_gem_object *obj); +int i915_gem_object_put_pages(struct drm_i915_gem_object *obj); void i915_gem_release_mmap(struct drm_i915_gem_object *obj); void i915_gem_lastclose(struct drm_device *dev); diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index 313bdbaba3cd..9d33fb3f8d42 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -1662,7 +1662,7 @@ i915_gem_object_put_pages_gtt(struct drm_i915_gem_object *obj) kfree(obj->pages); } -static int +int i915_gem_object_put_pages(struct drm_i915_gem_object *obj) { const struct drm_i915_gem_object_ops *ops = obj->ops; From 43e28f092b2fa4ebc46bdc210134a80610815785 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Tue, 8 Jan 2013 10:53:09 +0000 Subject: [PATCH 007/101] drm/i915: Bail if we attempt to allocate pages for a purged object Move the existing checking inside bind_to_gtt() to the more appropriate layer in order to prevent recreation of the pages after they have been explicitly truncated. Signed-off-by: Chris Wilson Reviewed-by: Imre Deak Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_gem.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index 9d33fb3f8d42..a2bb18914329 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -1828,6 +1828,11 @@ i915_gem_object_get_pages(struct drm_i915_gem_object *obj) if (obj->pages) return 0; + if (obj->madv != I915_MADV_WILLNEED) { + DRM_ERROR("Attempting to obtain a purgeable object\n"); + return -EINVAL; + } + BUG_ON(obj->pages_pin_count); ret = ops->get_pages(obj); @@ -2440,7 +2445,7 @@ int i915_gem_object_unbind(struct drm_i915_gem_object *obj) { drm_i915_private_t *dev_priv = obj->base.dev->dev_private; - int ret = 0; + int ret; if (obj->gtt_space == NULL) return 0; @@ -2880,11 +2885,6 @@ i915_gem_object_bind_to_gtt(struct drm_i915_gem_object *obj, bool mappable, fenceable; int ret; - if (obj->madv != I915_MADV_WILLNEED) { - DRM_ERROR("Attempting to bind a purgeable object\n"); - return -EINVAL; - } - fence_size = i915_gem_get_gtt_size(dev, obj->base.size, obj->tiling_mode); From 419fa72a1973c9ba2fd2c2505dc889f54b857459 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Tue, 8 Jan 2013 10:53:13 +0000 Subject: [PATCH 008/101] drm/i915: Mark a temporary allocation for copy-from-user as such The difference is that the kernel will then know that this memory will be reclaimable in the near future. Signed-off-by: Chris Wilson Reviewed-by: Imre Deak Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_gem_execbuffer.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/i915_gem_execbuffer.c b/drivers/gpu/drm/i915/i915_gem_execbuffer.c index 163bb52bd3b3..986eb98f0d25 100644 --- a/drivers/gpu/drm/i915/i915_gem_execbuffer.c +++ b/drivers/gpu/drm/i915/i915_gem_execbuffer.c @@ -1113,7 +1113,7 @@ i915_gem_execbuffer2(struct drm_device *dev, void *data, } exec2_list = kmalloc(sizeof(*exec2_list)*args->buffer_count, - GFP_KERNEL | __GFP_NOWARN | __GFP_NORETRY); + GFP_TEMPORARY | __GFP_NOWARN | __GFP_NORETRY); if (exec2_list == NULL) exec2_list = drm_malloc_ab(sizeof(*exec2_list), args->buffer_count); From 3b96eff447b4ca34ca8ccd42e2651be2955f34b4 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Tue, 8 Jan 2013 10:53:14 +0000 Subject: [PATCH 009/101] drm/i915: Take the handle idr spinlock once for looking up the exec objects Signed-off-by: Chris Wilson Reviewed-by: Imre Deak Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_gem_execbuffer.c | 86 ++++++++++++---------- 1 file changed, 46 insertions(+), 40 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_gem_execbuffer.c b/drivers/gpu/drm/i915/i915_gem_execbuffer.c index 986eb98f0d25..da103c179e3f 100644 --- a/drivers/gpu/drm/i915/i915_gem_execbuffer.c +++ b/drivers/gpu/drm/i915/i915_gem_execbuffer.c @@ -69,6 +69,46 @@ eb_add_object(struct eb_objects *eb, struct drm_i915_gem_object *obj) &eb->buckets[obj->exec_handle & eb->and]); } +static int +eb_lookup_objects(struct eb_objects *eb, + struct drm_i915_gem_exec_object2 *exec, + int count, + struct drm_file *file, + struct list_head *objects) +{ + int i; + + spin_lock(&file->table_lock); + for (i = 0; i < count; i++) { + struct drm_i915_gem_object *obj; + + obj = to_intel_bo(idr_find(&file->object_idr, exec[i].handle)); + if (obj == NULL) { + spin_unlock(&file->table_lock); + DRM_DEBUG("Invalid object handle %d at index %d\n", + exec[i].handle, i); + return -ENOENT; + } + + if (!list_empty(&obj->exec_list)) { + spin_unlock(&file->table_lock); + DRM_DEBUG("Object %p [handle %d, index %d] appears more than once in object list\n", + obj, exec[i].handle, i); + return -EINVAL; + } + + drm_gem_object_reference(&obj->base); + list_add_tail(&obj->exec_list, objects); + + obj->exec_handle = exec[i].handle; + obj->exec_entry = &exec[i]; + eb_add_object(eb, obj); + } + spin_unlock(&file->table_lock); + + return 0; +} + static struct drm_i915_gem_object * eb_get_object(struct eb_objects *eb, unsigned long handle) { @@ -550,21 +590,9 @@ i915_gem_execbuffer_relocate_slow(struct drm_device *dev, /* reacquire the objects */ eb_reset(eb); - for (i = 0; i < count; i++) { - obj = to_intel_bo(drm_gem_object_lookup(dev, file, - exec[i].handle)); - if (&obj->base == NULL) { - DRM_DEBUG("Invalid object handle %d at index %d\n", - exec[i].handle, i); - ret = -ENOENT; - goto err; - } - - list_add_tail(&obj->exec_list, objects); - obj->exec_handle = exec[i].handle; - obj->exec_entry = &exec[i]; - eb_add_object(eb, obj); - } + ret = eb_lookup_objects(eb, exec, count, file, objects); + if (ret) + goto err; ret = i915_gem_execbuffer_reserve(ring, file, objects); if (ret) @@ -872,31 +900,9 @@ i915_gem_do_execbuffer(struct drm_device *dev, void *data, /* Look up object handles */ INIT_LIST_HEAD(&objects); - for (i = 0; i < args->buffer_count; i++) { - struct drm_i915_gem_object *obj; - - obj = to_intel_bo(drm_gem_object_lookup(dev, file, - exec[i].handle)); - if (&obj->base == NULL) { - DRM_DEBUG("Invalid object handle %d at index %d\n", - exec[i].handle, i); - /* prevent error path from reading uninitialized data */ - ret = -ENOENT; - goto err; - } - - if (!list_empty(&obj->exec_list)) { - DRM_DEBUG("Object %p [handle %d, index %d] appears more than once in object list\n", - obj, exec[i].handle, i); - ret = -EINVAL; - goto err; - } - - list_add_tail(&obj->exec_list, &objects); - obj->exec_handle = exec[i].handle; - obj->exec_entry = &exec[i]; - eb_add_object(eb, obj); - } + ret = eb_lookup_objects(eb, exec, args->buffer_count, file, &objects); + if (ret) + goto err; /* take note of the batch buffer before we might reorder the lists */ batch_obj = list_entry(objects.prev, From bcffc3faa692d6b2ef734e4f0c8f097175284db6 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Tue, 8 Jan 2013 10:53:15 +0000 Subject: [PATCH 010/101] drm/i915: Move the execbuffer objects list from the stack into the tracker Instead of passing around the eb-objects hashtable and a separate object list, we can include the object list into the eb-objects structure for convenience. Signed-off-by: Chris Wilson Reviewed-by: Imre Deak Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_gem_execbuffer.c | 58 ++++++++++------------ 1 file changed, 27 insertions(+), 31 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_gem_execbuffer.c b/drivers/gpu/drm/i915/i915_gem_execbuffer.c index da103c179e3f..386677f8fd38 100644 --- a/drivers/gpu/drm/i915/i915_gem_execbuffer.c +++ b/drivers/gpu/drm/i915/i915_gem_execbuffer.c @@ -34,6 +34,7 @@ #include struct eb_objects { + struct list_head objects; int and; struct hlist_head buckets[0]; }; @@ -53,6 +54,7 @@ eb_create(int size) return eb; eb->and = count - 1; + INIT_LIST_HEAD(&eb->objects); return eb; } @@ -73,8 +75,7 @@ static int eb_lookup_objects(struct eb_objects *eb, struct drm_i915_gem_exec_object2 *exec, int count, - struct drm_file *file, - struct list_head *objects) + struct drm_file *file) { int i; @@ -98,7 +99,7 @@ eb_lookup_objects(struct eb_objects *eb, } drm_gem_object_reference(&obj->base); - list_add_tail(&obj->exec_list, objects); + list_add_tail(&obj->exec_list, &eb->objects); obj->exec_handle = exec[i].handle; obj->exec_entry = &exec[i]; @@ -129,6 +130,15 @@ eb_get_object(struct eb_objects *eb, unsigned long handle) static void eb_destroy(struct eb_objects *eb) { + while (!list_empty(&eb->objects)) { + struct drm_i915_gem_object *obj; + + obj = list_first_entry(&eb->objects, + struct drm_i915_gem_object, + exec_list); + list_del_init(&obj->exec_list); + drm_gem_object_unreference(&obj->base); + } kfree(eb); } @@ -328,8 +338,7 @@ i915_gem_execbuffer_relocate_object_slow(struct drm_i915_gem_object *obj, static int i915_gem_execbuffer_relocate(struct drm_device *dev, - struct eb_objects *eb, - struct list_head *objects) + struct eb_objects *eb) { struct drm_i915_gem_object *obj; int ret = 0; @@ -342,7 +351,7 @@ i915_gem_execbuffer_relocate(struct drm_device *dev, * lockdep complains vehemently. */ pagefault_disable(); - list_for_each_entry(obj, objects, exec_list) { + list_for_each_entry(obj, &eb->objects, exec_list) { ret = i915_gem_execbuffer_relocate_object(obj, eb); if (ret) break; @@ -531,7 +540,6 @@ static int i915_gem_execbuffer_relocate_slow(struct drm_device *dev, struct drm_file *file, struct intel_ring_buffer *ring, - struct list_head *objects, struct eb_objects *eb, struct drm_i915_gem_exec_object2 *exec, int count) @@ -542,8 +550,8 @@ i915_gem_execbuffer_relocate_slow(struct drm_device *dev, int i, total, ret; /* We may process another execbuffer during the unlock... */ - while (!list_empty(objects)) { - obj = list_first_entry(objects, + while (!list_empty(&eb->objects)) { + obj = list_first_entry(&eb->objects, struct drm_i915_gem_object, exec_list); list_del_init(&obj->exec_list); @@ -590,15 +598,15 @@ i915_gem_execbuffer_relocate_slow(struct drm_device *dev, /* reacquire the objects */ eb_reset(eb); - ret = eb_lookup_objects(eb, exec, count, file, objects); + ret = eb_lookup_objects(eb, exec, count, file); if (ret) goto err; - ret = i915_gem_execbuffer_reserve(ring, file, objects); + ret = i915_gem_execbuffer_reserve(ring, file, &eb->objects); if (ret) goto err; - list_for_each_entry(obj, objects, exec_list) { + list_for_each_entry(obj, &eb->objects, exec_list) { int offset = obj->exec_entry - exec; ret = i915_gem_execbuffer_relocate_object_slow(obj, eb, reloc + reloc_offset[offset]); @@ -756,7 +764,6 @@ i915_gem_do_execbuffer(struct drm_device *dev, void *data, struct drm_i915_gem_exec_object2 *exec) { drm_i915_private_t *dev_priv = dev->dev_private; - struct list_head objects; struct eb_objects *eb; struct drm_i915_gem_object *batch_obj; struct drm_clip_rect *cliprects = NULL; @@ -899,28 +906,26 @@ i915_gem_do_execbuffer(struct drm_device *dev, void *data, } /* Look up object handles */ - INIT_LIST_HEAD(&objects); - ret = eb_lookup_objects(eb, exec, args->buffer_count, file, &objects); + ret = eb_lookup_objects(eb, exec, args->buffer_count, file); if (ret) goto err; /* take note of the batch buffer before we might reorder the lists */ - batch_obj = list_entry(objects.prev, + batch_obj = list_entry(eb->objects.prev, struct drm_i915_gem_object, exec_list); /* Move the objects en-masse into the GTT, evicting if necessary. */ - ret = i915_gem_execbuffer_reserve(ring, file, &objects); + ret = i915_gem_execbuffer_reserve(ring, file, &eb->objects); if (ret) goto err; /* The objects are in their final locations, apply the relocations. */ - ret = i915_gem_execbuffer_relocate(dev, eb, &objects); + ret = i915_gem_execbuffer_relocate(dev, eb); if (ret) { if (ret == -EFAULT) { ret = i915_gem_execbuffer_relocate_slow(dev, file, ring, - &objects, eb, - exec, + eb, exec, args->buffer_count); BUG_ON(!mutex_is_locked(&dev->struct_mutex)); } @@ -943,7 +948,7 @@ i915_gem_do_execbuffer(struct drm_device *dev, void *data, if (flags & I915_DISPATCH_SECURE && !batch_obj->has_global_gtt_mapping) i915_gem_gtt_bind_object(batch_obj, batch_obj->cache_level); - ret = i915_gem_execbuffer_move_to_gpu(ring, &objects); + ret = i915_gem_execbuffer_move_to_gpu(ring, &eb->objects); if (ret) goto err; @@ -997,20 +1002,11 @@ i915_gem_do_execbuffer(struct drm_device *dev, void *data, trace_i915_gem_ring_dispatch(ring, intel_ring_get_seqno(ring), flags); - i915_gem_execbuffer_move_to_active(&objects, ring); + i915_gem_execbuffer_move_to_active(&eb->objects, ring); i915_gem_execbuffer_retire_commands(dev, file, ring); err: eb_destroy(eb); - while (!list_empty(&objects)) { - struct drm_i915_gem_object *obj; - - obj = list_first_entry(&objects, - struct drm_i915_gem_object, - exec_list); - list_del_init(&obj->exec_list); - drm_gem_object_unreference(&obj->base); - } mutex_unlock(&dev->struct_mutex); From ed5982e6ce5f106abcbf071f80730db344a6da42 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Thu, 17 Jan 2013 22:23:36 +0100 Subject: [PATCH 011/101] drm/i915: Allow userspace to hint that the relocations were known Userspace is able to hint to the kernel that its command stream and auxiliary state buffers already hold the correct presumed addresses and so the relocation process may be skipped if the kernel does not need to move any buffers in preparation for the execbuffer. Thus for the common case where the allotment of buffers is static between batches, we can avoid the overhead of individually checking the relocation entries. Note that this requires userspace to supply the domain tracking and requests for workarounds itself that would otherwise be computed based upon the relocation entries. Using copywinwin10 as an example that is dependent upon emitting a lot of relocations (2 per operation), we see improvements of: c2d/gm45: 618000.0/sec to 632000.0/sec. i3-330m: 748000.0/sec to 830000.0/sec. (measured relative to a baseline with neither optimisations applied). Signed-off-by: Chris Wilson Reviewed-by: Imre Deak [danvet: Fixup merge conflict in userspace header due to different baseline trees.] Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_dma.c | 3 + drivers/gpu/drm/i915/i915_gem_execbuffer.c | 68 ++++++++++++++-------- include/uapi/drm/i915_drm.h | 14 +++++ 3 files changed, 62 insertions(+), 23 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_dma.c b/drivers/gpu/drm/i915/i915_dma.c index 6d8a1dc74934..a6e047d533ec 100644 --- a/drivers/gpu/drm/i915/i915_dma.c +++ b/drivers/gpu/drm/i915/i915_dma.c @@ -992,6 +992,9 @@ static int i915_getparam(struct drm_device *dev, void *data, case I915_PARAM_HAS_PINNED_BATCHES: value = 1; break; + case I915_PARAM_HAS_EXEC_NO_RELOC: + value = 1; + break; default: DRM_DEBUG_DRIVER("Unknown parameter %d\n", param->param); diff --git a/drivers/gpu/drm/i915/i915_gem_execbuffer.c b/drivers/gpu/drm/i915/i915_gem_execbuffer.c index 386677f8fd38..34f6cdffa9f8 100644 --- a/drivers/gpu/drm/i915/i915_gem_execbuffer.c +++ b/drivers/gpu/drm/i915/i915_gem_execbuffer.c @@ -373,7 +373,8 @@ need_reloc_mappable(struct drm_i915_gem_object *obj) static int i915_gem_execbuffer_reserve_object(struct drm_i915_gem_object *obj, - struct intel_ring_buffer *ring) + struct intel_ring_buffer *ring, + bool *need_reloc) { struct drm_i915_private *dev_priv = obj->base.dev->dev_private; struct drm_i915_gem_exec_object2 *entry = obj->exec_entry; @@ -414,7 +415,20 @@ i915_gem_execbuffer_reserve_object(struct drm_i915_gem_object *obj, obj->has_aliasing_ppgtt_mapping = 1; } - entry->offset = obj->gtt_offset; + if (entry->offset != obj->gtt_offset) { + entry->offset = obj->gtt_offset; + *need_reloc = true; + } + + if (entry->flags & EXEC_OBJECT_WRITE) { + obj->base.pending_read_domains = I915_GEM_DOMAIN_RENDER; + obj->base.pending_write_domain = I915_GEM_DOMAIN_RENDER; + } + + if (entry->flags & EXEC_OBJECT_NEEDS_GTT && + !obj->has_global_gtt_mapping) + i915_gem_gtt_bind_object(obj, obj->cache_level); + return 0; } @@ -440,7 +454,8 @@ i915_gem_execbuffer_unreserve_object(struct drm_i915_gem_object *obj) static int i915_gem_execbuffer_reserve(struct intel_ring_buffer *ring, struct drm_file *file, - struct list_head *objects) + struct list_head *objects, + bool *need_relocs) { struct drm_i915_gem_object *obj; struct list_head ordered_objects; @@ -468,7 +483,7 @@ i915_gem_execbuffer_reserve(struct intel_ring_buffer *ring, else list_move_tail(&obj->exec_list, &ordered_objects); - obj->base.pending_read_domains = 0; + obj->base.pending_read_domains = I915_GEM_GPU_DOMAINS & ~I915_GEM_DOMAIN_COMMAND; obj->base.pending_write_domain = 0; obj->pending_fenced_gpu_access = false; } @@ -508,7 +523,7 @@ i915_gem_execbuffer_reserve(struct intel_ring_buffer *ring, (need_mappable && !obj->map_and_fenceable)) ret = i915_gem_object_unbind(obj); else - ret = i915_gem_execbuffer_reserve_object(obj, ring); + ret = i915_gem_execbuffer_reserve_object(obj, ring, need_relocs); if (ret) goto err; } @@ -518,7 +533,7 @@ i915_gem_execbuffer_reserve(struct intel_ring_buffer *ring, if (obj->gtt_space) continue; - ret = i915_gem_execbuffer_reserve_object(obj, ring); + ret = i915_gem_execbuffer_reserve_object(obj, ring, need_relocs); if (ret) goto err; } @@ -538,16 +553,18 @@ err: /* Decrement pin count for bound objects */ static int i915_gem_execbuffer_relocate_slow(struct drm_device *dev, + struct drm_i915_gem_execbuffer2 *args, struct drm_file *file, struct intel_ring_buffer *ring, struct eb_objects *eb, - struct drm_i915_gem_exec_object2 *exec, - int count) + struct drm_i915_gem_exec_object2 *exec) { struct drm_i915_gem_relocation_entry *reloc; struct drm_i915_gem_object *obj; + bool need_relocs; int *reloc_offset; int i, total, ret; + int count = args->buffer_count; /* We may process another execbuffer during the unlock... */ while (!list_empty(&eb->objects)) { @@ -602,7 +619,8 @@ i915_gem_execbuffer_relocate_slow(struct drm_device *dev, if (ret) goto err; - ret = i915_gem_execbuffer_reserve(ring, file, &eb->objects); + need_relocs = (args->flags & I915_EXEC_NO_RELOC) == 0; + ret = i915_gem_execbuffer_reserve(ring, file, &eb->objects, &need_relocs); if (ret) goto err; @@ -660,6 +678,9 @@ i915_gem_execbuffer_move_to_gpu(struct intel_ring_buffer *ring, static bool i915_gem_check_execbuffer(struct drm_i915_gem_execbuffer2 *exec) { + if (exec->flags & __I915_EXEC_UNKNOWN_FLAGS) + return false; + return ((exec->batch_start_offset | exec->batch_len) & 0x7) == 0; } @@ -673,6 +694,9 @@ validate_exec_list(struct drm_i915_gem_exec_object2 *exec, char __user *ptr = (char __user *)(uintptr_t)exec[i].relocs_ptr; int length; /* limited by fault_in_pages_readable() */ + if (exec[i].flags & __EXEC_OBJECT_UNKNOWN_FLAGS) + return -EINVAL; + /* First check for malicious input causing overflow */ if (exec[i].relocation_count > INT_MAX / sizeof(struct drm_i915_gem_relocation_entry)) @@ -680,9 +704,6 @@ validate_exec_list(struct drm_i915_gem_exec_object2 *exec, length = exec[i].relocation_count * sizeof(struct drm_i915_gem_relocation_entry); - if (!access_ok(VERIFY_READ, ptr, length)) - return -EFAULT; - /* we may also need to update the presumed offsets */ if (!access_ok(VERIFY_WRITE, ptr, length)) return -EFAULT; @@ -704,8 +725,10 @@ i915_gem_execbuffer_move_to_active(struct list_head *objects, u32 old_read = obj->base.read_domains; u32 old_write = obj->base.write_domain; - obj->base.read_domains = obj->base.pending_read_domains; obj->base.write_domain = obj->base.pending_write_domain; + if (obj->base.write_domain == 0) + obj->base.pending_read_domains |= obj->base.read_domains; + obj->base.read_domains = obj->base.pending_read_domains; obj->fenced_gpu_access = obj->pending_fenced_gpu_access; i915_gem_object_move_to_active(obj, ring); @@ -770,14 +793,12 @@ i915_gem_do_execbuffer(struct drm_device *dev, void *data, struct intel_ring_buffer *ring; u32 ctx_id = i915_execbuffer2_get_context_id(*args); u32 exec_start, exec_len; - u32 mask; - u32 flags; + u32 mask, flags; int ret, mode, i; + bool need_relocs; - if (!i915_gem_check_execbuffer(args)) { - DRM_DEBUG("execbuf with invalid offset/length\n"); + if (!i915_gem_check_execbuffer(args)) return -EINVAL; - } ret = validate_exec_list(exec, args->buffer_count); if (ret) @@ -916,17 +937,18 @@ i915_gem_do_execbuffer(struct drm_device *dev, void *data, exec_list); /* Move the objects en-masse into the GTT, evicting if necessary. */ - ret = i915_gem_execbuffer_reserve(ring, file, &eb->objects); + need_relocs = (args->flags & I915_EXEC_NO_RELOC) == 0; + ret = i915_gem_execbuffer_reserve(ring, file, &eb->objects, &need_relocs); if (ret) goto err; /* The objects are in their final locations, apply the relocations. */ - ret = i915_gem_execbuffer_relocate(dev, eb); + if (need_relocs) + ret = i915_gem_execbuffer_relocate(dev, eb); if (ret) { if (ret == -EFAULT) { - ret = i915_gem_execbuffer_relocate_slow(dev, file, ring, - eb, exec, - args->buffer_count); + ret = i915_gem_execbuffer_relocate_slow(dev, args, file, ring, + eb, exec); BUG_ON(!mutex_is_locked(&dev->struct_mutex)); } if (ret) diff --git a/include/uapi/drm/i915_drm.h b/include/uapi/drm/i915_drm.h index c4d2e9c74002..2430b6ad6a85 100644 --- a/include/uapi/drm/i915_drm.h +++ b/include/uapi/drm/i915_drm.h @@ -308,6 +308,7 @@ typedef struct drm_i915_irq_wait { #define I915_PARAM_RSVD_FOR_FUTURE_USE 22 #define I915_PARAM_HAS_SECURE_BATCHES 23 #define I915_PARAM_HAS_PINNED_BATCHES 24 +#define I915_PARAM_HAS_EXEC_NO_RELOC 25 typedef struct drm_i915_getparam { int param; @@ -628,7 +629,11 @@ struct drm_i915_gem_exec_object2 { __u64 offset; #define EXEC_OBJECT_NEEDS_FENCE (1<<0) +#define EXEC_OBJECT_NEEDS_GTT (1<<1) +#define EXEC_OBJECT_WRITE (1<<2) +#define __EXEC_OBJECT_UNKNOWN_FLAGS -(EXEC_OBJECT_WRITE<<1) __u64 flags; + __u64 rsvd1; __u64 rsvd2; }; @@ -687,6 +692,15 @@ struct drm_i915_gem_execbuffer2 { */ #define I915_EXEC_IS_PINNED (1<<10) +/** Provide a hint to the kernel that the command stream and auxilliary + * state buffers already holds the correct presumed addresses and so the + * relocation process may be skipped if no buffers need to be moved in + * preparation for the execbuffer. + */ +#define I915_EXEC_NO_RELOC (1<<11) + +#define __I915_EXEC_UNKNOWN_FLAGS -(I915_EXEC_NO_RELOC<<1) + #define I915_EXEC_CONTEXT_ID_MASK (0xffffffff) #define i915_execbuffer2_set_context_id(eb2, context) \ (eb2).rsvd1 = context & I915_EXEC_CONTEXT_ID_MASK From eef90ccb8a4d50b219a95cc53878ebb007315b32 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Tue, 8 Jan 2013 10:53:17 +0000 Subject: [PATCH 012/101] drm/i915: Use the reloc.handle as an index into the execbuffer array Using copywinwin10 as an example that is dependent upon emitting a lot of relocations (2 per operation), we see improvements of: c2d/gm45: 618000.0/sec to 623000.0/sec. i3-330m: 748000.0/sec to 789000.0/sec. (measured relative to a baseline with neither optimisations applied). Signed-off-by: Chris Wilson Reviewed-by: Imre Deak Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_dma.c | 3 + drivers/gpu/drm/i915/i915_gem_execbuffer.c | 98 +++++++++++++--------- include/uapi/drm/i915_drm.h | 8 +- 3 files changed, 70 insertions(+), 39 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_dma.c b/drivers/gpu/drm/i915/i915_dma.c index a6e047d533ec..442118293883 100644 --- a/drivers/gpu/drm/i915/i915_dma.c +++ b/drivers/gpu/drm/i915/i915_dma.c @@ -995,6 +995,9 @@ static int i915_getparam(struct drm_device *dev, void *data, case I915_PARAM_HAS_EXEC_NO_RELOC: value = 1; break; + case I915_PARAM_HAS_EXEC_HANDLE_LUT: + value = 1; + break; default: DRM_DEBUG_DRIVER("Unknown parameter %d\n", param->param); diff --git a/drivers/gpu/drm/i915/i915_gem_execbuffer.c b/drivers/gpu/drm/i915/i915_gem_execbuffer.c index 34f6cdffa9f8..f5a11ecf5494 100644 --- a/drivers/gpu/drm/i915/i915_gem_execbuffer.c +++ b/drivers/gpu/drm/i915/i915_gem_execbuffer.c @@ -36,24 +36,40 @@ struct eb_objects { struct list_head objects; int and; - struct hlist_head buckets[0]; + union { + struct drm_i915_gem_object *lut[0]; + struct hlist_head buckets[0]; + }; }; static struct eb_objects * -eb_create(int size) +eb_create(struct drm_i915_gem_execbuffer2 *args) { - struct eb_objects *eb; - int count = PAGE_SIZE / sizeof(struct hlist_head) / 2; - BUILD_BUG_ON(!is_power_of_2(PAGE_SIZE / sizeof(struct hlist_head))); - while (count > size) - count >>= 1; - eb = kzalloc(count*sizeof(struct hlist_head) + - sizeof(struct eb_objects), - GFP_KERNEL); - if (eb == NULL) - return eb; + struct eb_objects *eb = NULL; + + if (args->flags & I915_EXEC_HANDLE_LUT) { + int size = args->buffer_count; + size *= sizeof(struct drm_i915_gem_object *); + size += sizeof(struct eb_objects); + eb = kmalloc(size, GFP_TEMPORARY | __GFP_NOWARN | __GFP_NORETRY); + } + + if (eb == NULL) { + int size = args->buffer_count; + int count = PAGE_SIZE / sizeof(struct hlist_head) / 2; + BUILD_BUG_ON(!is_power_of_2(PAGE_SIZE / sizeof(struct hlist_head))); + while (count > 2*size) + count >>= 1; + eb = kzalloc(count*sizeof(struct hlist_head) + + sizeof(struct eb_objects), + GFP_TEMPORARY); + if (eb == NULL) + return eb; + + eb->and = count - 1; + } else + eb->and = -args->buffer_count; - eb->and = count - 1; INIT_LIST_HEAD(&eb->objects); return eb; } @@ -61,26 +77,20 @@ eb_create(int size) static void eb_reset(struct eb_objects *eb) { - memset(eb->buckets, 0, (eb->and+1)*sizeof(struct hlist_head)); -} - -static void -eb_add_object(struct eb_objects *eb, struct drm_i915_gem_object *obj) -{ - hlist_add_head(&obj->exec_node, - &eb->buckets[obj->exec_handle & eb->and]); + if (eb->and >= 0) + memset(eb->buckets, 0, (eb->and+1)*sizeof(struct hlist_head)); } static int eb_lookup_objects(struct eb_objects *eb, struct drm_i915_gem_exec_object2 *exec, - int count, + const struct drm_i915_gem_execbuffer2 *args, struct drm_file *file) { int i; spin_lock(&file->table_lock); - for (i = 0; i < count; i++) { + for (i = 0; i < args->buffer_count; i++) { struct drm_i915_gem_object *obj; obj = to_intel_bo(idr_find(&file->object_idr, exec[i].handle)); @@ -101,9 +111,15 @@ eb_lookup_objects(struct eb_objects *eb, drm_gem_object_reference(&obj->base); list_add_tail(&obj->exec_list, &eb->objects); - obj->exec_handle = exec[i].handle; obj->exec_entry = &exec[i]; - eb_add_object(eb, obj); + if (eb->and < 0) { + eb->lut[i] = obj; + } else { + uint32_t handle = args->flags & I915_EXEC_HANDLE_LUT ? i : exec[i].handle; + obj->exec_handle = handle; + hlist_add_head(&obj->exec_node, + &eb->buckets[handle & eb->and]); + } } spin_unlock(&file->table_lock); @@ -113,18 +129,24 @@ eb_lookup_objects(struct eb_objects *eb, static struct drm_i915_gem_object * eb_get_object(struct eb_objects *eb, unsigned long handle) { - struct hlist_head *head; - struct hlist_node *node; - struct drm_i915_gem_object *obj; + if (eb->and < 0) { + if (handle >= -eb->and) + return NULL; + return eb->lut[handle]; + } else { + struct hlist_head *head; + struct hlist_node *node; - head = &eb->buckets[handle & eb->and]; - hlist_for_each(node, head) { - obj = hlist_entry(node, struct drm_i915_gem_object, exec_node); - if (obj->exec_handle == handle) - return obj; + head = &eb->buckets[handle & eb->and]; + hlist_for_each(node, head) { + struct drm_i915_gem_object *obj; + + obj = hlist_entry(node, struct drm_i915_gem_object, exec_node); + if (obj->exec_handle == handle) + return obj; + } + return NULL; } - - return NULL; } static void @@ -615,7 +637,7 @@ i915_gem_execbuffer_relocate_slow(struct drm_device *dev, /* reacquire the objects */ eb_reset(eb); - ret = eb_lookup_objects(eb, exec, count, file); + ret = eb_lookup_objects(eb, exec, args, file); if (ret) goto err; @@ -919,7 +941,7 @@ i915_gem_do_execbuffer(struct drm_device *dev, void *data, goto pre_mutex_err; } - eb = eb_create(args->buffer_count); + eb = eb_create(args); if (eb == NULL) { mutex_unlock(&dev->struct_mutex); ret = -ENOMEM; @@ -927,7 +949,7 @@ i915_gem_do_execbuffer(struct drm_device *dev, void *data, } /* Look up object handles */ - ret = eb_lookup_objects(eb, exec, args->buffer_count, file); + ret = eb_lookup_objects(eb, exec, args, file); if (ret) goto err; diff --git a/include/uapi/drm/i915_drm.h b/include/uapi/drm/i915_drm.h index 2430b6ad6a85..07d59419fe6b 100644 --- a/include/uapi/drm/i915_drm.h +++ b/include/uapi/drm/i915_drm.h @@ -309,6 +309,7 @@ typedef struct drm_i915_irq_wait { #define I915_PARAM_HAS_SECURE_BATCHES 23 #define I915_PARAM_HAS_PINNED_BATCHES 24 #define I915_PARAM_HAS_EXEC_NO_RELOC 25 +#define I915_PARAM_HAS_EXEC_HANDLE_LUT 26 typedef struct drm_i915_getparam { int param; @@ -699,7 +700,12 @@ struct drm_i915_gem_execbuffer2 { */ #define I915_EXEC_NO_RELOC (1<<11) -#define __I915_EXEC_UNKNOWN_FLAGS -(I915_EXEC_NO_RELOC<<1) +/** Use the reloc.handle as an index into the exec object array rather + * than as the per-file handle. + */ +#define I915_EXEC_HANDLE_LUT (1<<12) + +#define __I915_EXEC_UNKNOWN_FLAGS -(I915_EXEC_HANDLE_LUT<<1) #define I915_EXEC_CONTEXT_ID_MASK (0xffffffff) #define i915_execbuffer2_set_context_id(eb2, context) \ From c70af1e4b60a1853feeaae2bf6e2aa98de68acd9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Wed, 16 Jan 2013 19:59:03 +0200 Subject: [PATCH 013/101] drm/i915: Fix SPRITE0_FLIP_DONE_INT_EN_VLV and SPRITE0_FLIPDONE_INT_STATUS_VLV MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fix up some copypaste errors in the PIPESTAT register for VLV. SPRITE0_FLIP_DONE_INT_EN_VLV is bit 22, not bit 26. SPRITE0_FLIPDONE_INT_STATUS_VLV is bit 14, not bit 15. Signed-off-by: Ville Syrjälä Reviewed-by: Jesse Barnes Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_reg.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index 3b039f4268e3..4c33bd2bd4e6 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -2672,7 +2672,7 @@ #define PIPE_VSYNC_INTERRUPT_ENABLE (1UL<<25) #define PIPE_DISPLAY_LINE_COMPARE_ENABLE (1UL<<24) #define PIPE_DPST_EVENT_ENABLE (1UL<<23) -#define SPRITE0_FLIP_DONE_INT_EN_VLV (1UL<<26) +#define SPRITE0_FLIP_DONE_INT_EN_VLV (1UL<<22) #define PIPE_LEGACY_BLC_EVENT_ENABLE (1UL<<22) #define PIPE_ODD_FIELD_INTERRUPT_ENABLE (1UL<<21) #define PIPE_EVEN_FIELD_INTERRUPT_ENABLE (1UL<<20) @@ -2682,7 +2682,7 @@ #define PIPEA_HBLANK_INT_EN_VLV (1UL<<16) #define PIPE_OVERLAY_UPDATED_ENABLE (1UL<<16) #define SPRITE1_FLIPDONE_INT_STATUS_VLV (1UL<<15) -#define SPRITE0_FLIPDONE_INT_STATUS_VLV (1UL<<15) +#define SPRITE0_FLIPDONE_INT_STATUS_VLV (1UL<<14) #define PIPE_CRC_ERROR_INTERRUPT_STATUS (1UL<<13) #define PIPE_CRC_DONE_INTERRUPT_STATUS (1UL<<12) #define PIPE_GMBUS_INTERRUPT_STATUS (1UL<<11) From c1fc6521efbed7d3aca4e37ac61b23300f161cd1 Mon Sep 17 00:00:00 2001 From: Ben Widawsky Date: Thu, 17 Jan 2013 12:45:12 -0800 Subject: [PATCH 014/101] drm/i915: Kill gtt_end It's duplicated in the more useful gtt_total. Reviewed-by: Rodrigo Vivi Signed-off-by: Ben Widawsky Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_drv.h | 1 - drivers/gpu/drm/i915/i915_gem_gtt.c | 3 +-- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 8f5b2816fc03..d58189e60844 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -801,7 +801,6 @@ typedef struct drm_i915_private { /** Usable portion of the GTT for GEM */ unsigned long gtt_start; unsigned long gtt_mappable_end; - unsigned long gtt_end; unsigned long stolen_base; /* limited to low memory (32-bit) */ /** "Graphics Stolen Memory" holds the global PTEs */ diff --git a/drivers/gpu/drm/i915/i915_gem_gtt.c b/drivers/gpu/drm/i915/i915_gem_gtt.c index a4af0f79e972..3ffcf528f166 100644 --- a/drivers/gpu/drm/i915/i915_gem_gtt.c +++ b/drivers/gpu/drm/i915/i915_gem_gtt.c @@ -394,7 +394,7 @@ void i915_gem_restore_gtt_mappings(struct drm_device *dev) /* First fill our portion of the GTT with scratch pages */ i915_ggtt_clear_range(dev, dev_priv->mm.gtt_start / PAGE_SIZE, - (dev_priv->mm.gtt_end - dev_priv->mm.gtt_start) / PAGE_SIZE); + dev_priv->mm.gtt_total / PAGE_SIZE); list_for_each_entry(obj, &dev_priv->mm.bound_list, gtt_list) { i915_gem_clflush_object(obj); @@ -556,7 +556,6 @@ void i915_gem_setup_global_gtt(struct drm_device *dev, dev_priv->mm.gtt_start = start; dev_priv->mm.gtt_mappable_end = mappable_end; - dev_priv->mm.gtt_end = end; dev_priv->mm.gtt_total = end - start; dev_priv->mm.mappable_gtt_total = min(end, mappable_end) - start; From 35451cb6fbd3655ede4694b11761a587d400d647 Mon Sep 17 00:00:00 2001 From: Ben Widawsky Date: Thu, 17 Jan 2013 12:45:13 -0800 Subject: [PATCH 015/101] drm/i915: Mappable_end can't ever be > end Both DRI1 and DRI2 can never specify a mappable size which goes past the GTT size. Don't pretend otherwise. Reviewed-by: Rodrigo Vivi Signed-off-by: Ben Widawsky Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_gem_gtt.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/i915_gem_gtt.c b/drivers/gpu/drm/i915/i915_gem_gtt.c index 3ffcf528f166..e66c70008767 100644 --- a/drivers/gpu/drm/i915/i915_gem_gtt.c +++ b/drivers/gpu/drm/i915/i915_gem_gtt.c @@ -536,6 +536,8 @@ void i915_gem_setup_global_gtt(struct drm_device *dev, struct drm_i915_gem_object *obj; unsigned long hole_start, hole_end; + BUG_ON(mappable_end > end); + /* Subtract the guard page ... */ drm_mm_init(&dev_priv->mm.gtt_space, start, end - start - PAGE_SIZE); if (!HAS_LLC(dev)) @@ -557,7 +559,7 @@ void i915_gem_setup_global_gtt(struct drm_device *dev, dev_priv->mm.gtt_start = start; dev_priv->mm.gtt_mappable_end = mappable_end; dev_priv->mm.gtt_total = end - start; - dev_priv->mm.mappable_gtt_total = min(end, mappable_end) - start; + dev_priv->mm.mappable_gtt_total = mappable_end - start; /* Clear any non-preallocated blocks */ drm_mm_for_each_hole(entry, &dev_priv->mm.gtt_space, From 00fc2c3c53d7bfc9a29e5f4bdf2677f0c399f3bc Mon Sep 17 00:00:00 2001 From: Ben Widawsky Date: Thu, 17 Jan 2013 12:45:14 -0800 Subject: [PATCH 016/101] drm/i915: Remove gtt_mappable_total With the assertion from the previous patch in place, it should be safe to get rid gtt_mappable_total. Keeps things saner to not have to track the same info in two places. In order to keep the diff as simple as possible and keep with the existing gtt_setup semantics we opt to keep gtt_mappable_end. It's not as consistent with the 'total' used in the previous patch, but that can be fixed later. Reviewed-by: Rodrigo Vivi [Ben modified commit message] Signed-off-by: Ben Widawsky Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_debugfs.c | 3 ++- drivers/gpu/drm/i915/i915_drv.h | 1 - drivers/gpu/drm/i915/i915_gem_gtt.c | 1 - 3 files changed, 2 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_debugfs.c b/drivers/gpu/drm/i915/i915_debugfs.c index f94418bd1ed2..35d326d70fab 100644 --- a/drivers/gpu/drm/i915/i915_debugfs.c +++ b/drivers/gpu/drm/i915/i915_debugfs.c @@ -259,7 +259,8 @@ static int i915_gem_object_info(struct seq_file *m, void* data) count, size); seq_printf(m, "%zu [%zu] gtt total\n", - dev_priv->mm.gtt_total, dev_priv->mm.mappable_gtt_total); + dev_priv->mm.gtt_total, + dev_priv->mm.gtt_mappable_end - dev_priv->mm.gtt_start); mutex_unlock(&dev->struct_mutex); diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index d58189e60844..6e2c10b65c8d 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -886,7 +886,6 @@ typedef struct drm_i915_private { /* accounting, useful for userland debugging */ size_t gtt_total; - size_t mappable_gtt_total; size_t object_memory; u32 object_count; } mm; diff --git a/drivers/gpu/drm/i915/i915_gem_gtt.c b/drivers/gpu/drm/i915/i915_gem_gtt.c index e66c70008767..8c42ddd467b6 100644 --- a/drivers/gpu/drm/i915/i915_gem_gtt.c +++ b/drivers/gpu/drm/i915/i915_gem_gtt.c @@ -559,7 +559,6 @@ void i915_gem_setup_global_gtt(struct drm_device *dev, dev_priv->mm.gtt_start = start; dev_priv->mm.gtt_mappable_end = mappable_end; dev_priv->mm.gtt_total = end - start; - dev_priv->mm.mappable_gtt_total = mappable_end - start; /* Clear any non-preallocated blocks */ drm_mm_for_each_hole(entry, &dev_priv->mm.gtt_space, From 5d4545aef561ad47f91bcf75814af20c104b5a9e Mon Sep 17 00:00:00 2001 From: Ben Widawsky Date: Thu, 17 Jan 2013 12:45:15 -0800 Subject: [PATCH 017/101] drm/i915: Create a gtt structure The purpose of the gtt structure is to help isolate our gtt specific properties from the rest of the code (in doing so it help us finish the isolation from the AGP connection). The following members are pulled out (and renamed): gtt_start gtt_total gtt_mappable_end gtt_mappable gtt_base_addr gsm The gtt structure will serve as a nice place to put gen specific gtt routines in upcoming patches. As far as what else I feel belongs in this structure: it is meant to encapsulate the GTT's physical properties. This is why I've not added fields which track various drm_mm properties, or things like gtt_mtrr (which is itself a pretty transient field). Reviewed-by: Rodrigo Vivi [Ben modified commit messages] Signed-off-by: Ben Widawsky Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_debugfs.c | 4 +-- drivers/gpu/drm/i915/i915_dma.c | 20 +++++++-------- drivers/gpu/drm/i915/i915_drv.h | 29 ++++++++++++++++------ drivers/gpu/drm/i915/i915_gem.c | 14 +++++------ drivers/gpu/drm/i915/i915_gem_evict.c | 2 +- drivers/gpu/drm/i915/i915_gem_execbuffer.c | 2 +- drivers/gpu/drm/i915/i915_gem_gtt.c | 24 +++++++++--------- drivers/gpu/drm/i915/i915_gem_tiling.c | 2 +- drivers/gpu/drm/i915/i915_irq.c | 4 +-- drivers/gpu/drm/i915/intel_display.c | 2 +- drivers/gpu/drm/i915/intel_fb.c | 2 +- drivers/gpu/drm/i915/intel_overlay.c | 4 +-- 12 files changed, 61 insertions(+), 48 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_debugfs.c b/drivers/gpu/drm/i915/i915_debugfs.c index 35d326d70fab..773b23ecc83b 100644 --- a/drivers/gpu/drm/i915/i915_debugfs.c +++ b/drivers/gpu/drm/i915/i915_debugfs.c @@ -259,8 +259,8 @@ static int i915_gem_object_info(struct seq_file *m, void* data) count, size); seq_printf(m, "%zu [%zu] gtt total\n", - dev_priv->mm.gtt_total, - dev_priv->mm.gtt_mappable_end - dev_priv->mm.gtt_start); + dev_priv->gtt.total, + dev_priv->gtt.mappable_end - dev_priv->gtt.start); mutex_unlock(&dev->struct_mutex); diff --git a/drivers/gpu/drm/i915/i915_dma.c b/drivers/gpu/drm/i915/i915_dma.c index 442118293883..bb622135798a 100644 --- a/drivers/gpu/drm/i915/i915_dma.c +++ b/drivers/gpu/drm/i915/i915_dma.c @@ -1076,7 +1076,7 @@ static int i915_set_status_page(struct drm_device *dev, void *data, ring->status_page.gfx_addr = hws->addr & (0x1ffff<<12); dev_priv->dri1.gfx_hws_cpu_addr = - ioremap_wc(dev_priv->mm.gtt_base_addr + hws->addr, 4096); + ioremap_wc(dev_priv->gtt.mappable_base + hws->addr, 4096); if (dev_priv->dri1.gfx_hws_cpu_addr == NULL) { i915_dma_cleanup(dev); ring->status_page.gfx_addr = 0; @@ -1543,17 +1543,17 @@ int i915_driver_load(struct drm_device *dev, unsigned long flags) } aperture_size = dev_priv->mm.gtt->gtt_mappable_entries << PAGE_SHIFT; - dev_priv->mm.gtt_base_addr = dev_priv->mm.gtt->gma_bus_addr; + dev_priv->gtt.mappable_base = dev_priv->mm.gtt->gma_bus_addr; - dev_priv->mm.gtt_mapping = - io_mapping_create_wc(dev_priv->mm.gtt_base_addr, + dev_priv->gtt.mappable = + io_mapping_create_wc(dev_priv->gtt.mappable_base, aperture_size); - if (dev_priv->mm.gtt_mapping == NULL) { + if (dev_priv->gtt.mappable == NULL) { ret = -EIO; goto out_rmmap; } - i915_mtrr_setup(dev_priv, dev_priv->mm.gtt_base_addr, + i915_mtrr_setup(dev_priv, dev_priv->gtt.mappable_base, aperture_size); /* The i915 workqueue is primarily used for batched retirement of @@ -1658,11 +1658,11 @@ out_gem_unload: out_mtrrfree: if (dev_priv->mm.gtt_mtrr >= 0) { mtrr_del(dev_priv->mm.gtt_mtrr, - dev_priv->mm.gtt_base_addr, + dev_priv->gtt.mappable_base, aperture_size); dev_priv->mm.gtt_mtrr = -1; } - io_mapping_free(dev_priv->mm.gtt_mapping); + io_mapping_free(dev_priv->gtt.mappable); out_rmmap: pci_iounmap(dev->pdev, dev_priv->regs); put_gmch: @@ -1696,10 +1696,10 @@ int i915_driver_unload(struct drm_device *dev) /* Cancel the retire work handler, which should be idle now. */ cancel_delayed_work_sync(&dev_priv->mm.retire_work); - io_mapping_free(dev_priv->mm.gtt_mapping); + io_mapping_free(dev_priv->gtt.mappable); if (dev_priv->mm.gtt_mtrr >= 0) { mtrr_del(dev_priv->mm.gtt_mtrr, - dev_priv->mm.gtt_base_addr, + dev_priv->gtt.mappable_base, dev_priv->mm.gtt->gtt_mappable_entries * PAGE_SIZE); dev_priv->mm.gtt_mtrr = -1; } diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 6e2c10b65c8d..f3f2e5e1393f 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -364,6 +364,25 @@ struct intel_device_info { u8 has_llc:1; }; +/* The Graphics Translation Table is the way in which GEN hardware translates a + * Graphics Virtual Address into a Physical Address. In addition to the normal + * collateral associated with any va->pa translations GEN hardware also has a + * portion of the GTT which can be mapped by the CPU and remain both coherent + * and correct (in cases like swizzling). That region is referred to as GMADR in + * the spec. + */ +struct i915_gtt { + unsigned long start; /* Start offset of used GTT */ + size_t total; /* Total size GTT can map */ + + unsigned long mappable_end; /* End offset that we can CPU map */ + struct io_mapping *mappable; /* Mapping to our CPU mappable region */ + phys_addr_t mappable_base; /* PA of our GMADR */ + + /** "Graphics Stolen Memory" holds the global PTEs */ + void __iomem *gsm; +}; + #define I915_PPGTT_PD_ENTRIES 512 #define I915_PPGTT_PT_ENTRIES 1024 struct i915_hw_ppgtt { @@ -781,6 +800,8 @@ typedef struct drm_i915_private { /* Register state */ bool modeset_on_lid; + struct i915_gtt gtt; + struct { /** Bridge to intel-gtt-ko */ struct intel_gtt *gtt; @@ -799,15 +820,8 @@ typedef struct drm_i915_private { struct list_head unbound_list; /** Usable portion of the GTT for GEM */ - unsigned long gtt_start; - unsigned long gtt_mappable_end; unsigned long stolen_base; /* limited to low memory (32-bit) */ - /** "Graphics Stolen Memory" holds the global PTEs */ - void __iomem *gsm; - - struct io_mapping *gtt_mapping; - phys_addr_t gtt_base_addr; int gtt_mtrr; /** PPGTT used for aliasing the PPGTT with the GTT */ @@ -885,7 +899,6 @@ typedef struct drm_i915_private { struct drm_i915_gem_phys_object *phys_objs[I915_MAX_PHYS_OBJECT]; /* accounting, useful for userland debugging */ - size_t gtt_total; size_t object_memory; u32 object_count; } mm; diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index a2bb18914329..51fdf16181a7 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -186,7 +186,7 @@ i915_gem_get_aperture_ioctl(struct drm_device *dev, void *data, pinned += obj->gtt_space->size; mutex_unlock(&dev->struct_mutex); - args->aper_size = dev_priv->mm.gtt_total; + args->aper_size = dev_priv->gtt.total; args->aper_available_size = args->aper_size - pinned; return 0; @@ -637,7 +637,7 @@ i915_gem_gtt_pwrite_fast(struct drm_device *dev, * source page isn't available. Return the error and we'll * retry in the slow path. */ - if (fast_user_write(dev_priv->mm.gtt_mapping, page_base, + if (fast_user_write(dev_priv->gtt.mappable, page_base, page_offset, user_data, page_length)) { ret = -EFAULT; goto out_unpin; @@ -1362,7 +1362,7 @@ int i915_gem_fault(struct vm_area_struct *vma, struct vm_fault *vmf) obj->fault_mappable = true; - pfn = ((dev_priv->mm.gtt_base_addr + obj->gtt_offset) >> PAGE_SHIFT) + + pfn = ((dev_priv->gtt.mappable_base + obj->gtt_offset) >> PAGE_SHIFT) + page_offset; /* Finally, remap it using the new GTT offset */ @@ -1544,7 +1544,7 @@ i915_gem_mmap_gtt(struct drm_file *file, goto unlock; } - if (obj->base.size > dev_priv->mm.gtt_mappable_end) { + if (obj->base.size > dev_priv->gtt.mappable_end) { ret = -E2BIG; goto out; } @@ -2910,7 +2910,7 @@ i915_gem_object_bind_to_gtt(struct drm_i915_gem_object *obj, * before evicting everything in a vain attempt to find space. */ if (obj->base.size > - (map_and_fenceable ? dev_priv->mm.gtt_mappable_end : dev_priv->mm.gtt_total)) { + (map_and_fenceable ? dev_priv->gtt.mappable_end : dev_priv->gtt.total)) { DRM_ERROR("Attempting to bind an object larger than the aperture\n"); return -E2BIG; } @@ -2931,7 +2931,7 @@ i915_gem_object_bind_to_gtt(struct drm_i915_gem_object *obj, if (map_and_fenceable) ret = drm_mm_insert_node_in_range_generic(&dev_priv->mm.gtt_space, node, size, alignment, obj->cache_level, - 0, dev_priv->mm.gtt_mappable_end); + 0, dev_priv->gtt.mappable_end); else ret = drm_mm_insert_node_generic(&dev_priv->mm.gtt_space, node, size, alignment, obj->cache_level); @@ -2971,7 +2971,7 @@ i915_gem_object_bind_to_gtt(struct drm_i915_gem_object *obj, (node->start & (fence_alignment - 1)) == 0; mappable = - obj->gtt_offset + obj->base.size <= dev_priv->mm.gtt_mappable_end; + obj->gtt_offset + obj->base.size <= dev_priv->gtt.mappable_end; obj->map_and_fenceable = mappable && fenceable; diff --git a/drivers/gpu/drm/i915/i915_gem_evict.c b/drivers/gpu/drm/i915/i915_gem_evict.c index 776a3225184c..c86d5d9356fd 100644 --- a/drivers/gpu/drm/i915/i915_gem_evict.c +++ b/drivers/gpu/drm/i915/i915_gem_evict.c @@ -80,7 +80,7 @@ i915_gem_evict_something(struct drm_device *dev, int min_size, if (mappable) drm_mm_init_scan_with_range(&dev_priv->mm.gtt_space, min_size, alignment, cache_level, - 0, dev_priv->mm.gtt_mappable_end); + 0, dev_priv->gtt.mappable_end); else drm_mm_init_scan(&dev_priv->mm.gtt_space, min_size, alignment, cache_level); diff --git a/drivers/gpu/drm/i915/i915_gem_execbuffer.c b/drivers/gpu/drm/i915/i915_gem_execbuffer.c index f5a11ecf5494..27269103b621 100644 --- a/drivers/gpu/drm/i915/i915_gem_execbuffer.c +++ b/drivers/gpu/drm/i915/i915_gem_execbuffer.c @@ -281,7 +281,7 @@ i915_gem_execbuffer_relocate_entry(struct drm_i915_gem_object *obj, /* Map the page containing the relocation we're going to perform. */ reloc->offset += obj->gtt_offset; - reloc_page = io_mapping_map_atomic_wc(dev_priv->mm.gtt_mapping, + reloc_page = io_mapping_map_atomic_wc(dev_priv->gtt.mappable, reloc->offset & PAGE_MASK); reloc_entry = (uint32_t __iomem *) (reloc_page + (reloc->offset & ~PAGE_MASK)); diff --git a/drivers/gpu/drm/i915/i915_gem_gtt.c b/drivers/gpu/drm/i915/i915_gem_gtt.c index 8c42ddd467b6..61bfb12e1016 100644 --- a/drivers/gpu/drm/i915/i915_gem_gtt.c +++ b/drivers/gpu/drm/i915/i915_gem_gtt.c @@ -290,7 +290,7 @@ void i915_gem_init_ppgtt(struct drm_device *dev) return; - pd_addr = (gtt_pte_t __iomem*)dev_priv->mm.gsm + ppgtt->pd_offset/sizeof(gtt_pte_t); + pd_addr = (gtt_pte_t __iomem*)dev_priv->gtt.gsm + ppgtt->pd_offset/sizeof(gtt_pte_t); for (i = 0; i < ppgtt->num_pd_entries; i++) { dma_addr_t pt_addr; @@ -367,7 +367,7 @@ static void i915_ggtt_clear_range(struct drm_device *dev, { struct drm_i915_private *dev_priv = dev->dev_private; gtt_pte_t scratch_pte; - gtt_pte_t __iomem *gtt_base = (gtt_pte_t __iomem *) dev_priv->mm.gsm + first_entry; + gtt_pte_t __iomem *gtt_base = (gtt_pte_t __iomem *) dev_priv->gtt.gsm + first_entry; const int max_entries = dev_priv->mm.gtt->gtt_total_entries - first_entry; int i; @@ -393,8 +393,8 @@ void i915_gem_restore_gtt_mappings(struct drm_device *dev) struct drm_i915_gem_object *obj; /* First fill our portion of the GTT with scratch pages */ - i915_ggtt_clear_range(dev, dev_priv->mm.gtt_start / PAGE_SIZE, - dev_priv->mm.gtt_total / PAGE_SIZE); + i915_ggtt_clear_range(dev, dev_priv->gtt.start / PAGE_SIZE, + dev_priv->gtt.total / PAGE_SIZE); list_for_each_entry(obj, &dev_priv->mm.bound_list, gtt_list) { i915_gem_clflush_object(obj); @@ -433,7 +433,7 @@ static void gen6_ggtt_bind_object(struct drm_i915_gem_object *obj, const int first_entry = obj->gtt_space->start >> PAGE_SHIFT; const int max_entries = dev_priv->mm.gtt->gtt_total_entries - first_entry; gtt_pte_t __iomem *gtt_entries = - (gtt_pte_t __iomem *)dev_priv->mm.gsm + first_entry; + (gtt_pte_t __iomem *)dev_priv->gtt.gsm + first_entry; int unused, i = 0; unsigned int len, m = 0; dma_addr_t addr; @@ -556,9 +556,9 @@ void i915_gem_setup_global_gtt(struct drm_device *dev, obj->has_global_gtt_mapping = 1; } - dev_priv->mm.gtt_start = start; - dev_priv->mm.gtt_mappable_end = mappable_end; - dev_priv->mm.gtt_total = end - start; + dev_priv->gtt.start = start; + dev_priv->gtt.mappable_end = mappable_end; + dev_priv->gtt.total = end - start; /* Clear any non-preallocated blocks */ drm_mm_for_each_hole(entry, &dev_priv->mm.gtt_space, @@ -752,9 +752,9 @@ int i915_gem_gtt_init(struct drm_device *dev) goto err_out; } - dev_priv->mm.gsm = ioremap_wc(gtt_bus_addr, - dev_priv->mm.gtt->gtt_total_entries * sizeof(gtt_pte_t)); - if (!dev_priv->mm.gsm) { + dev_priv->gtt.gsm = ioremap_wc(gtt_bus_addr, + dev_priv->mm.gtt->gtt_total_entries * sizeof(gtt_pte_t)); + if (!dev_priv->gtt.gsm) { DRM_ERROR("Failed to map the gtt page table\n"); teardown_scratch_page(dev); ret = -ENOMEM; @@ -778,7 +778,7 @@ err_out: void i915_gem_gtt_fini(struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; - iounmap(dev_priv->mm.gsm); + iounmap(dev_priv->gtt.gsm); teardown_scratch_page(dev); if (INTEL_INFO(dev)->gen < 6) intel_gmch_remove(); diff --git a/drivers/gpu/drm/i915/i915_gem_tiling.c b/drivers/gpu/drm/i915/i915_gem_tiling.c index e76f0d8470a1..abcba2f5a788 100644 --- a/drivers/gpu/drm/i915/i915_gem_tiling.c +++ b/drivers/gpu/drm/i915/i915_gem_tiling.c @@ -357,7 +357,7 @@ i915_gem_set_tiling(struct drm_device *dev, void *data, obj->map_and_fenceable = obj->gtt_space == NULL || - (obj->gtt_offset + obj->base.size <= dev_priv->mm.gtt_mappable_end && + (obj->gtt_offset + obj->base.size <= dev_priv->gtt.mappable_end && i915_gem_object_fence_ok(obj, args->tiling_mode)); /* Rebind if we need a change of alignment */ diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c index 202813128441..cc49a6ddc052 100644 --- a/drivers/gpu/drm/i915/i915_irq.c +++ b/drivers/gpu/drm/i915/i915_irq.c @@ -939,7 +939,7 @@ i915_error_object_create(struct drm_i915_private *dev_priv, goto unwind; local_irq_save(flags); - if (reloc_offset < dev_priv->mm.gtt_mappable_end && + if (reloc_offset < dev_priv->gtt.mappable_end && src->has_global_gtt_mapping) { void __iomem *s; @@ -948,7 +948,7 @@ i915_error_object_create(struct drm_i915_private *dev_priv, * captures what the GPU read. */ - s = io_mapping_map_atomic_wc(dev_priv->mm.gtt_mapping, + s = io_mapping_map_atomic_wc(dev_priv->gtt.mappable, reloc_offset); memcpy_fromio(d, s, PAGE_SIZE); io_mapping_unmap_atomic(s); diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 40b6b5e9d6ef..e4c5067a54d3 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -8687,7 +8687,7 @@ void intel_modeset_init(struct drm_device *dev) dev->mode_config.max_width = 8192; dev->mode_config.max_height = 8192; } - dev->mode_config.fb_base = dev_priv->mm.gtt_base_addr; + dev->mode_config.fb_base = dev_priv->gtt.mappable_base; DRM_DEBUG_KMS("%d display pipe%s available.\n", dev_priv->num_pipe, dev_priv->num_pipe > 1 ? "s" : ""); diff --git a/drivers/gpu/drm/i915/intel_fb.c b/drivers/gpu/drm/i915/intel_fb.c index 71d55801c0d9..ce02af8ca96e 100644 --- a/drivers/gpu/drm/i915/intel_fb.c +++ b/drivers/gpu/drm/i915/intel_fb.c @@ -142,7 +142,7 @@ static int intelfb_create(struct intel_fbdev *ifbdev, info->fix.smem_len = size; info->screen_base = - ioremap_wc(dev_priv->mm.gtt_base_addr + obj->gtt_offset, + ioremap_wc(dev_priv->gtt.mappable_base + obj->gtt_offset, size); if (!info->screen_base) { ret = -ENOSPC; diff --git a/drivers/gpu/drm/i915/intel_overlay.c b/drivers/gpu/drm/i915/intel_overlay.c index fabe0acf808d..ba978bf93a2e 100644 --- a/drivers/gpu/drm/i915/intel_overlay.c +++ b/drivers/gpu/drm/i915/intel_overlay.c @@ -195,7 +195,7 @@ intel_overlay_map_regs(struct intel_overlay *overlay) if (OVERLAY_NEEDS_PHYSICAL(overlay->dev)) regs = (struct overlay_registers __iomem *)overlay->reg_bo->phys_obj->handle->vaddr; else - regs = io_mapping_map_wc(dev_priv->mm.gtt_mapping, + regs = io_mapping_map_wc(dev_priv->gtt.mappable, overlay->reg_bo->gtt_offset); return regs; @@ -1434,7 +1434,7 @@ intel_overlay_map_regs_atomic(struct intel_overlay *overlay) regs = (struct overlay_registers __iomem *) overlay->reg_bo->phys_obj->handle->vaddr; else - regs = io_mapping_map_atomic_wc(dev_priv->mm.gtt_mapping, + regs = io_mapping_map_atomic_wc(dev_priv->gtt.mappable, overlay->reg_bo->gtt_offset); return regs; From dabb7a91ae6442d642a52e0de22d781a8ad2af12 Mon Sep 17 00:00:00 2001 From: Ben Widawsky Date: Thu, 17 Jan 2013 12:45:16 -0800 Subject: [PATCH 018/101] drm/i915: Remove use on gma_bus_addr on gen6+ We have enough info to not use the intel_gtt bridge stuff. v2: Move setup of mappable_base above the legacy init stuff because we still need that on older platforms. (Daniel) v3: Remove the dev_priv hunk which was rebased in by accident Reviewed-by: Rodrigo Vivi (v2) Signed-off-by: Ben Widawsky Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_dma.c | 3 +-- drivers/gpu/drm/i915/i915_gem_gtt.c | 3 ++- drivers/gpu/drm/i915/intel_ringbuffer.c | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_dma.c b/drivers/gpu/drm/i915/i915_dma.c index bb622135798a..468d2a0fc378 100644 --- a/drivers/gpu/drm/i915/i915_dma.c +++ b/drivers/gpu/drm/i915/i915_dma.c @@ -1426,7 +1426,7 @@ static void i915_kick_out_firmware_fb(struct drm_i915_private *dev_priv) if (!ap) return; - ap->ranges[0].base = dev_priv->mm.gtt->gma_bus_addr; + ap->ranges[0].base = dev_priv->gtt.mappable_base; ap->ranges[0].size = dev_priv->mm.gtt->gtt_mappable_entries << PAGE_SHIFT; primary = @@ -1543,7 +1543,6 @@ int i915_driver_load(struct drm_device *dev, unsigned long flags) } aperture_size = dev_priv->mm.gtt->gtt_mappable_entries << PAGE_SHIFT; - dev_priv->gtt.mappable_base = dev_priv->mm.gtt->gma_bus_addr; dev_priv->gtt.mappable = io_mapping_create_wc(dev_priv->gtt.mappable_base, diff --git a/drivers/gpu/drm/i915/i915_gem_gtt.c b/drivers/gpu/drm/i915/i915_gem_gtt.c index 61bfb12e1016..0b8930577953 100644 --- a/drivers/gpu/drm/i915/i915_gem_gtt.c +++ b/drivers/gpu/drm/i915/i915_gem_gtt.c @@ -691,6 +691,8 @@ int i915_gem_gtt_init(struct drm_device *dev) u16 snb_gmch_ctl; int ret; + dev_priv->gtt.mappable_base = pci_resource_start(dev->pdev, 2); + /* On modern platforms we need not worry ourself with the legacy * hostbridge query stuff. Skip it entirely */ @@ -723,7 +725,6 @@ int i915_gem_gtt_init(struct drm_device *dev) /* For GEN6+ the PTEs for the ggtt live at 2MB + BAR0 */ gtt_bus_addr = pci_resource_start(dev->pdev, 0) + (2<<20); - dev_priv->mm.gtt->gma_bus_addr = pci_resource_start(dev->pdev, 2); /* i9xx_setup */ pci_read_config_word(dev->pdev, SNB_GMCH_CTRL, &snb_gmch_ctl); diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.c b/drivers/gpu/drm/i915/intel_ringbuffer.c index 59e02691baf3..ce1d07487402 100644 --- a/drivers/gpu/drm/i915/intel_ringbuffer.c +++ b/drivers/gpu/drm/i915/intel_ringbuffer.c @@ -1203,7 +1203,7 @@ static int intel_init_ring_buffer(struct drm_device *dev, goto err_unpin; ring->virtual_start = - ioremap_wc(dev_priv->mm.gtt->gma_bus_addr + obj->gtt_offset, + ioremap_wc(dev_priv->gtt.mappable_base + obj->gtt_offset, ring->size); if (ring->virtual_start == NULL) { DRM_ERROR("Failed to map ringbuffer.\n"); From 93d187993b783c68383a884091a600d9ad499ea6 Mon Sep 17 00:00:00 2001 From: Ben Widawsky Date: Thu, 17 Jan 2013 12:45:17 -0800 Subject: [PATCH 019/101] drm/i915: Remove use of gtt_mappable_entries Mappable_end, ie. size is almost always what you want as opposed to the number of entries. Since we already have that information, we can scrap the number of entries and only calculate it when needed. If gtt_start is !0, this will have slightly different behavior. This difference can only occur in DRI1, and exists when we try to kick out the firmware fb. The new code seems like a bugfix to me. The other case where we've changed the behavior is during init we check the mappable region against our current known upper and lower limits (64MB, and 512MB). This now matches the comment, and makes things more convenient after removing gtt_mappable_entries. Also worth noting is the setting of mappable_end is taken out of setup because we do it earlier now in the DRI2 case and therefore need to add that tiny hunk to support the DRI1 IOCTL. v2: Move up mappable end to before legacy AGP init v3: Add the dev_priv inclusion here from previous rebase error in patch 5 Reviewed-by: Rodrigo Vivi (v2) Signed-off-by: Ben Widawsky [danvet: squash in fix for a printk format flag mismatch warning.] Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_debugfs.c | 2 +- drivers/gpu/drm/i915/i915_dma.c | 8 ++++---- drivers/gpu/drm/i915/i915_gem.c | 2 ++ drivers/gpu/drm/i915/i915_gem_gtt.c | 15 +++++++-------- drivers/gpu/drm/i915/intel_fb.c | 3 +-- 5 files changed, 15 insertions(+), 15 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_debugfs.c b/drivers/gpu/drm/i915/i915_debugfs.c index 773b23ecc83b..90a6fc506dd5 100644 --- a/drivers/gpu/drm/i915/i915_debugfs.c +++ b/drivers/gpu/drm/i915/i915_debugfs.c @@ -258,7 +258,7 @@ static int i915_gem_object_info(struct seq_file *m, void* data) seq_printf(m, "%u fault mappable objects, %zu bytes\n", count, size); - seq_printf(m, "%zu [%zu] gtt total\n", + seq_printf(m, "%zu [%lu] gtt total\n", dev_priv->gtt.total, dev_priv->gtt.mappable_end - dev_priv->gtt.start); diff --git a/drivers/gpu/drm/i915/i915_dma.c b/drivers/gpu/drm/i915/i915_dma.c index 468d2a0fc378..3f70178c63ca 100644 --- a/drivers/gpu/drm/i915/i915_dma.c +++ b/drivers/gpu/drm/i915/i915_dma.c @@ -1427,8 +1427,8 @@ static void i915_kick_out_firmware_fb(struct drm_i915_private *dev_priv) return; ap->ranges[0].base = dev_priv->gtt.mappable_base; - ap->ranges[0].size = - dev_priv->mm.gtt->gtt_mappable_entries << PAGE_SHIFT; + ap->ranges[0].size = dev_priv->gtt.mappable_end - dev_priv->gtt.start; + primary = pdev->resource[PCI_ROM_RESOURCE].flags & IORESOURCE_ROM_SHADOW; @@ -1542,7 +1542,7 @@ int i915_driver_load(struct drm_device *dev, unsigned long flags) goto put_gmch; } - aperture_size = dev_priv->mm.gtt->gtt_mappable_entries << PAGE_SHIFT; + aperture_size = dev_priv->gtt.mappable_end; dev_priv->gtt.mappable = io_mapping_create_wc(dev_priv->gtt.mappable_base, @@ -1699,7 +1699,7 @@ int i915_driver_unload(struct drm_device *dev) if (dev_priv->mm.gtt_mtrr >= 0) { mtrr_del(dev_priv->mm.gtt_mtrr, dev_priv->gtt.mappable_base, - dev_priv->mm.gtt->gtt_mappable_entries * PAGE_SIZE); + dev_priv->gtt.mappable_end); dev_priv->mm.gtt_mtrr = -1; } diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index 51fdf16181a7..e4132ffb7609 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -149,6 +149,7 @@ int i915_gem_init_ioctl(struct drm_device *dev, void *data, struct drm_file *file) { + struct drm_i915_private *dev_priv = dev->dev_private; struct drm_i915_gem_init *args = data; if (drm_core_check_feature(dev, DRIVER_MODESET)) @@ -165,6 +166,7 @@ i915_gem_init_ioctl(struct drm_device *dev, void *data, mutex_lock(&dev->struct_mutex); i915_gem_setup_global_gtt(dev, args->gtt_start, args->gtt_end, args->gtt_end); + dev_priv->gtt.mappable_end = args->gtt_end; mutex_unlock(&dev->struct_mutex); return 0; diff --git a/drivers/gpu/drm/i915/i915_gem_gtt.c b/drivers/gpu/drm/i915/i915_gem_gtt.c index 0b8930577953..0f0db02c1e56 100644 --- a/drivers/gpu/drm/i915/i915_gem_gtt.c +++ b/drivers/gpu/drm/i915/i915_gem_gtt.c @@ -557,7 +557,6 @@ void i915_gem_setup_global_gtt(struct drm_device *dev, } dev_priv->gtt.start = start; - dev_priv->gtt.mappable_end = mappable_end; dev_priv->gtt.total = end - start; /* Clear any non-preallocated blocks */ @@ -596,7 +595,7 @@ void i915_gem_init_global_gtt(struct drm_device *dev) int ret; gtt_size = dev_priv->mm.gtt->gtt_total_entries << PAGE_SHIFT; - mappable_size = dev_priv->mm.gtt->gtt_mappable_entries << PAGE_SHIFT; + mappable_size = dev_priv->gtt.mappable_end; if (intel_enable_ppgtt(dev) && HAS_ALIASING_PPGTT(dev)) { /* PPGTT pdes are stolen from global gtt ptes, so shrink the @@ -692,6 +691,7 @@ int i915_gem_gtt_init(struct drm_device *dev) int ret; dev_priv->gtt.mappable_base = pci_resource_start(dev->pdev, 2); + dev_priv->gtt.mappable_end = pci_resource_len(dev->pdev, 2); /* On modern platforms we need not worry ourself with the legacy * hostbridge query stuff. Skip it entirely @@ -735,14 +735,13 @@ int i915_gem_gtt_init(struct drm_device *dev) else dev_priv->mm.gtt->stolen_size = gen7_get_stolen_size(snb_gmch_ctl); - dev_priv->mm.gtt->gtt_mappable_entries = pci_resource_len(dev->pdev, 2) >> PAGE_SHIFT; /* 64/512MB is the current min/max we actually know of, but this is just a * coarse sanity check. */ - if ((dev_priv->mm.gtt->gtt_mappable_entries >> 8) < 64 || - dev_priv->mm.gtt->gtt_mappable_entries > dev_priv->mm.gtt->gtt_total_entries) { - DRM_ERROR("Unknown GMADR entries (%d)\n", - dev_priv->mm.gtt->gtt_mappable_entries); + if ((dev_priv->gtt.mappable_end < (64<<20) || + (dev_priv->gtt.mappable_end > (512<<20)))) { + DRM_ERROR("Unknown GMADR size (%lx)\n", + dev_priv->gtt.mappable_end); ret = -ENXIO; goto err_out; } @@ -764,7 +763,7 @@ int i915_gem_gtt_init(struct drm_device *dev) /* GMADR is the PCI aperture used by SW to access tiled GFX surfaces in a linear fashion. */ DRM_INFO("Memory usable by graphics device = %dM\n", dev_priv->mm.gtt->gtt_total_entries >> 8); - DRM_DEBUG_DRIVER("GMADR size = %dM\n", dev_priv->mm.gtt->gtt_mappable_entries >> 8); + DRM_DEBUG_DRIVER("GMADR size = %ldM\n", dev_priv->gtt.mappable_end >> 20); DRM_DEBUG_DRIVER("GTT stolen size = %dM\n", dev_priv->mm.gtt->stolen_size >> 20); return 0; diff --git a/drivers/gpu/drm/i915/intel_fb.c b/drivers/gpu/drm/i915/intel_fb.c index ce02af8ca96e..ce5f54498426 100644 --- a/drivers/gpu/drm/i915/intel_fb.c +++ b/drivers/gpu/drm/i915/intel_fb.c @@ -135,8 +135,7 @@ static int intelfb_create(struct intel_fbdev *ifbdev, goto out_unpin; } info->apertures->ranges[0].base = dev->mode_config.fb_base; - info->apertures->ranges[0].size = - dev_priv->mm.gtt->gtt_mappable_entries << PAGE_SHIFT; + info->apertures->ranges[0].size = dev_priv->gtt.mappable_end; info->fix.smem_start = dev->mode_config.fb_base + obj->gtt_offset; info->fix.smem_len = size; From 3685a8f38f2c54bb6058c0e66ae0562f8ab84e66 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Thu, 17 Jan 2013 16:31:28 +0200 Subject: [PATCH 020/101] drm/i915: Fix RGB color range property for PCH platforms MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The RGB color range select bit on the DP/SDVO/HDMI registers disappeared when PCH was introduced, and instead a new PIPECONF bit was added that performs the same function. Add a new INTEL_MODE_LIMITED_COLOR_RANGE private mode flag, and set it in the encoder mode_fixup if limited color range is requested. Set the the PIPECONF bit 13 based on the flag. Experimentation showed that simply toggling the bit while the pipe is active doesn't work. We need to restart the pipe, which luckily already happens. The DP/SDVO/HDMI bit 8 is marked MBZ in the docs, so avoid setting it, although it doesn't seem to do any harm in practice. TODO: - the PIPECONF bit too seems to have disappeared from HSW. Need a volunteer to test if it's just a documentation issue or if it's really gone. If the bit is gone and no easy replacement is found, then I suppose we may need to use the pipe CSC unit to perform the range compression. v2: Use mode private_flags instead of intel_encoder virtual functions v3: Moved the intel_dp color_range handling after bpc check to help later patches Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=46800 Reviewed-by: Paulo Zanoni Signed-off-by: Ville Syrjälä Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_reg.h | 1 + drivers/gpu/drm/i915/intel_display.c | 5 +++++ drivers/gpu/drm/i915/intel_dp.c | 7 ++++++- drivers/gpu/drm/i915/intel_drv.h | 5 +++++ drivers/gpu/drm/i915/intel_hdmi.c | 5 +++++ drivers/gpu/drm/i915/intel_sdvo.c | 5 ++++- 6 files changed, 26 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index 4c33bd2bd4e6..2521617b55da 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -2650,6 +2650,7 @@ #define PIPECONF_INTERLACED_DBL_ILK (4 << 21) /* ilk/snb only */ #define PIPECONF_PFIT_PF_INTERLACED_DBL_ILK (5 << 21) /* ilk/snb only */ #define PIPECONF_CXSR_DOWNCLOCK (1<<16) +#define PIPECONF_COLOR_RANGE_SELECT (1 << 13) #define PIPECONF_BPC_MASK (0x7 << 5) #define PIPECONF_8BPC (0<<5) #define PIPECONF_10BPC (1<<5) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index e4c5067a54d3..b35902e5d925 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -5096,6 +5096,11 @@ static void ironlake_set_pipeconf(struct drm_crtc *crtc, else val |= PIPECONF_PROGRESSIVE; + if (adjusted_mode->private_flags & INTEL_MODE_LIMITED_COLOR_RANGE) + val |= PIPECONF_COLOR_RANGE_SELECT; + else + val &= ~PIPECONF_COLOR_RANGE_SELECT; + I915_WRITE(PIPECONF(pipe), val); POSTING_READ(PIPECONF(pipe)); } diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c index 5f12eb2d0fb5..d9956278a56e 100644 --- a/drivers/gpu/drm/i915/intel_dp.c +++ b/drivers/gpu/drm/i915/intel_dp.c @@ -763,6 +763,10 @@ intel_dp_mode_fixup(struct drm_encoder *encoder, return false; bpp = adjusted_mode->private_flags & INTEL_MODE_DP_FORCE_6BPC ? 18 : 24; + + if (intel_dp->color_range) + adjusted_mode->private_flags |= INTEL_MODE_LIMITED_COLOR_RANGE; + mode_rate = intel_dp_link_required(adjusted_mode->clock, bpp); for (clock = 0; clock <= max_clock; clock++) { @@ -967,7 +971,8 @@ intel_dp_mode_set(struct drm_encoder *encoder, struct drm_display_mode *mode, else intel_dp->DP |= DP_PLL_FREQ_270MHZ; } else if (!HAS_PCH_CPT(dev) || is_cpu_edp(intel_dp)) { - intel_dp->DP |= intel_dp->color_range; + if (!HAS_PCH_SPLIT(dev)) + intel_dp->DP |= intel_dp->color_range; if (adjusted_mode->flags & DRM_MODE_FLAG_PHSYNC) intel_dp->DP |= DP_SYNC_HS_HIGH; diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index 54a034c82061..4df47be84abd 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -109,6 +109,11 @@ * timings in the mode to prevent the crtc fixup from overwriting them. * Currently only lvds needs that. */ #define INTEL_MODE_CRTC_TIMINGS_SET (0x20) +/* + * Set when limited 16-235 (as opposed to full 0-255) RGB color range is + * to be used. + */ +#define INTEL_MODE_LIMITED_COLOR_RANGE (0x40) static inline void intel_mode_set_pixel_multiplier(struct drm_display_mode *mode, diff --git a/drivers/gpu/drm/i915/intel_hdmi.c b/drivers/gpu/drm/i915/intel_hdmi.c index 6387f9b0df99..f194d756a58c 100644 --- a/drivers/gpu/drm/i915/intel_hdmi.c +++ b/drivers/gpu/drm/i915/intel_hdmi.c @@ -766,6 +766,11 @@ bool intel_hdmi_mode_fixup(struct drm_encoder *encoder, const struct drm_display_mode *mode, struct drm_display_mode *adjusted_mode) { + struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(encoder); + + if (intel_hdmi->color_range) + adjusted_mode->private_flags |= INTEL_MODE_LIMITED_COLOR_RANGE; + return true; } diff --git a/drivers/gpu/drm/i915/intel_sdvo.c b/drivers/gpu/drm/i915/intel_sdvo.c index 153377bed66a..3b8491af1f23 100644 --- a/drivers/gpu/drm/i915/intel_sdvo.c +++ b/drivers/gpu/drm/i915/intel_sdvo.c @@ -1064,6 +1064,9 @@ static bool intel_sdvo_mode_fixup(struct drm_encoder *encoder, multiplier = intel_sdvo_get_pixel_multiplier(adjusted_mode); intel_mode_set_pixel_multiplier(adjusted_mode, multiplier); + if (intel_sdvo->color_range) + adjusted_mode->private_flags |= INTEL_MODE_LIMITED_COLOR_RANGE; + return true; } @@ -1153,7 +1156,7 @@ static void intel_sdvo_mode_set(struct drm_encoder *encoder, /* The real mode polarity is set by the SDVO commands, using * struct intel_sdvo_dtd. */ sdvox = SDVO_VSYNC_ACTIVE_HIGH | SDVO_HSYNC_ACTIVE_HIGH; - if (intel_sdvo->is_hdmi) + if (!HAS_PCH_SPLIT(dev) && intel_sdvo->is_hdmi) sdvox |= intel_sdvo->color_range; if (INTEL_INFO(dev)->gen < 5) sdvox |= SDVO_BORDER_ENABLE; From 55bc60db5988c8366751d3d04dd690698a53412c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Thu, 17 Jan 2013 16:31:29 +0200 Subject: [PATCH 021/101] drm/i915: Add "Automatic" mode for the "Broadcast RGB" property MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add a new "Automatic" mode to the "Broadcast RGB" range property. When selected the driver automagically selects between full range and limited range output. Based on CEA-861 [1] guidelines, limited range output is selected if the mode is a CEA mode, except 640x480. Otherwise full range output is used. Additionally DVI monitors should most likely default to full range always. As per DP1.2a [2] DisplayPort should always use full range for 18bpp, and otherwise will follow CEA-861 rules. NOTE: The default value for the property will now be "Automatic" so some people may be affected in case they're relying on the current full range default. [1] CEA-861-E - 5.1 Default Encoding Parameters [2] VESA DisplayPort Ver.1.2a - 5.1.1.1 Video Colorimetry v2: Use has_hdmi_sink to check if a HDMI monitor is present v3: Add information about relevant spec chapters Reviewed-by: Paulo Zanoni Signed-off-by: Ville Syrjälä Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_drv.h | 4 ++++ drivers/gpu/drm/i915/intel_dp.c | 32 +++++++++++++++++++++---- drivers/gpu/drm/i915/intel_drv.h | 2 ++ drivers/gpu/drm/i915/intel_hdmi.c | 29 +++++++++++++++++++---- drivers/gpu/drm/i915/intel_modes.c | 5 ++-- drivers/gpu/drm/i915/intel_sdvo.c | 38 ++++++++++++++++++++++++------ 6 files changed, 93 insertions(+), 17 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index f3f2e5e1393f..0a2a18b8a075 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -1811,5 +1811,9 @@ __i915_write(64, q) #define POSTING_READ(reg) (void)I915_READ_NOTRACE(reg) #define POSTING_READ16(reg) (void)I915_READ16_NOTRACE(reg) +/* "Broadcast RGB" property */ +#define INTEL_BROADCAST_RGB_AUTO 0 +#define INTEL_BROADCAST_RGB_FULL 1 +#define INTEL_BROADCAST_RGB_LIMITED 2 #endif diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c index d9956278a56e..1492706ed087 100644 --- a/drivers/gpu/drm/i915/intel_dp.c +++ b/drivers/gpu/drm/i915/intel_dp.c @@ -764,6 +764,18 @@ intel_dp_mode_fixup(struct drm_encoder *encoder, bpp = adjusted_mode->private_flags & INTEL_MODE_DP_FORCE_6BPC ? 18 : 24; + if (intel_dp->color_range_auto) { + /* + * See: + * CEA-861-E - 5.1 Default Encoding Parameters + * VESA DisplayPort Ver.1.2a - 5.1.1.1 Video Colorimetry + */ + if (bpp != 18 && drm_mode_cea_vic(adjusted_mode) > 1) + intel_dp->color_range = DP_COLOR_RANGE_16_235; + else + intel_dp->color_range = 0; + } + if (intel_dp->color_range) adjusted_mode->private_flags |= INTEL_MODE_LIMITED_COLOR_RANGE; @@ -2462,10 +2474,21 @@ intel_dp_set_property(struct drm_connector *connector, } if (property == dev_priv->broadcast_rgb_property) { - if (val == !!intel_dp->color_range) - return 0; - - intel_dp->color_range = val ? DP_COLOR_RANGE_16_235 : 0; + switch (val) { + case INTEL_BROADCAST_RGB_AUTO: + intel_dp->color_range_auto = true; + break; + case INTEL_BROADCAST_RGB_FULL: + intel_dp->color_range_auto = false; + intel_dp->color_range = 0; + break; + case INTEL_BROADCAST_RGB_LIMITED: + intel_dp->color_range_auto = false; + intel_dp->color_range = DP_COLOR_RANGE_16_235; + break; + default: + return -EINVAL; + } goto done; } @@ -2606,6 +2629,7 @@ intel_dp_add_properties(struct intel_dp *intel_dp, struct drm_connector *connect intel_attach_force_audio_property(connector); intel_attach_broadcast_rgb_property(connector); + intel_dp->color_range_auto = true; if (is_edp(intel_dp)) { drm_mode_create_scaling_mode_property(connector->dev); diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index 4df47be84abd..1a698c6f16e7 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -343,6 +343,7 @@ struct intel_hdmi { u32 sdvox_reg; int ddc_bus; uint32_t color_range; + bool color_range_auto; bool has_hdmi_sink; bool has_audio; enum hdmi_force_audio force_audio; @@ -362,6 +363,7 @@ struct intel_dp { bool has_audio; enum hdmi_force_audio force_audio; uint32_t color_range; + bool color_range_auto; uint8_t link_bw; uint8_t lane_count; uint8_t dpcd[DP_RECEIVER_CAP_SIZE]; diff --git a/drivers/gpu/drm/i915/intel_hdmi.c b/drivers/gpu/drm/i915/intel_hdmi.c index f194d756a58c..db67be66639b 100644 --- a/drivers/gpu/drm/i915/intel_hdmi.c +++ b/drivers/gpu/drm/i915/intel_hdmi.c @@ -768,6 +768,15 @@ bool intel_hdmi_mode_fixup(struct drm_encoder *encoder, { struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(encoder); + if (intel_hdmi->color_range_auto) { + /* See CEA-861-E - 5.1 Default Encoding Parameters */ + if (intel_hdmi->has_hdmi_sink && + drm_mode_cea_vic(adjusted_mode) > 1) + intel_hdmi->color_range = SDVO_COLOR_RANGE_16_235; + else + intel_hdmi->color_range = 0; + } + if (intel_hdmi->color_range) adjusted_mode->private_flags |= INTEL_MODE_LIMITED_COLOR_RANGE; @@ -912,10 +921,21 @@ intel_hdmi_set_property(struct drm_connector *connector, } if (property == dev_priv->broadcast_rgb_property) { - if (val == !!intel_hdmi->color_range) - return 0; - - intel_hdmi->color_range = val ? SDVO_COLOR_RANGE_16_235 : 0; + switch (val) { + case INTEL_BROADCAST_RGB_AUTO: + intel_hdmi->color_range_auto = true; + break; + case INTEL_BROADCAST_RGB_FULL: + intel_hdmi->color_range_auto = false; + intel_hdmi->color_range = 0; + break; + case INTEL_BROADCAST_RGB_LIMITED: + intel_hdmi->color_range_auto = false; + intel_hdmi->color_range = SDVO_COLOR_RANGE_16_235; + break; + default: + return -EINVAL; + } goto done; } @@ -964,6 +984,7 @@ intel_hdmi_add_properties(struct intel_hdmi *intel_hdmi, struct drm_connector *c { intel_attach_force_audio_property(connector); intel_attach_broadcast_rgb_property(connector); + intel_hdmi->color_range_auto = true; } void intel_hdmi_init_connector(struct intel_digital_port *intel_dig_port, diff --git a/drivers/gpu/drm/i915/intel_modes.c b/drivers/gpu/drm/i915/intel_modes.c index 49249bb97485..0e860f39933d 100644 --- a/drivers/gpu/drm/i915/intel_modes.c +++ b/drivers/gpu/drm/i915/intel_modes.c @@ -100,8 +100,9 @@ intel_attach_force_audio_property(struct drm_connector *connector) } static const struct drm_prop_enum_list broadcast_rgb_names[] = { - { 0, "Full" }, - { 1, "Limited 16:235" }, + { INTEL_BROADCAST_RGB_AUTO, "Automatic" }, + { INTEL_BROADCAST_RGB_FULL, "Full" }, + { INTEL_BROADCAST_RGB_LIMITED, "Limited 16:235" }, }; void diff --git a/drivers/gpu/drm/i915/intel_sdvo.c b/drivers/gpu/drm/i915/intel_sdvo.c index 3b8491af1f23..3e34a3592e32 100644 --- a/drivers/gpu/drm/i915/intel_sdvo.c +++ b/drivers/gpu/drm/i915/intel_sdvo.c @@ -103,6 +103,7 @@ struct intel_sdvo { * It is only valid when using TMDS encoding and 8 bit per color mode. */ uint32_t color_range; + bool color_range_auto; /** * This is set if we're going to treat the device as TV-out. @@ -1064,6 +1065,15 @@ static bool intel_sdvo_mode_fixup(struct drm_encoder *encoder, multiplier = intel_sdvo_get_pixel_multiplier(adjusted_mode); intel_mode_set_pixel_multiplier(adjusted_mode, multiplier); + if (intel_sdvo->color_range_auto) { + /* See CEA-861-E - 5.1 Default Encoding Parameters */ + if (intel_sdvo->has_hdmi_monitor && + drm_mode_cea_vic(adjusted_mode) > 1) + intel_sdvo->color_range = SDVO_COLOR_RANGE_16_235; + else + intel_sdvo->color_range = 0; + } + if (intel_sdvo->color_range) adjusted_mode->private_flags |= INTEL_MODE_LIMITED_COLOR_RANGE; @@ -1900,10 +1910,21 @@ intel_sdvo_set_property(struct drm_connector *connector, } if (property == dev_priv->broadcast_rgb_property) { - if (val == !!intel_sdvo->color_range) - return 0; - - intel_sdvo->color_range = val ? SDVO_COLOR_RANGE_16_235 : 0; + switch (val) { + case INTEL_BROADCAST_RGB_AUTO: + intel_sdvo->color_range_auto = true; + break; + case INTEL_BROADCAST_RGB_FULL: + intel_sdvo->color_range_auto = false; + intel_sdvo->color_range = 0; + break; + case INTEL_BROADCAST_RGB_LIMITED: + intel_sdvo->color_range_auto = false; + intel_sdvo->color_range = SDVO_COLOR_RANGE_16_235; + break; + default: + return -EINVAL; + } goto done; } @@ -2200,13 +2221,16 @@ intel_sdvo_connector_init(struct intel_sdvo_connector *connector, } static void -intel_sdvo_add_hdmi_properties(struct intel_sdvo_connector *connector) +intel_sdvo_add_hdmi_properties(struct intel_sdvo *intel_sdvo, + struct intel_sdvo_connector *connector) { struct drm_device *dev = connector->base.base.dev; intel_attach_force_audio_property(&connector->base.base); - if (INTEL_INFO(dev)->gen >= 4 && IS_MOBILE(dev)) + if (INTEL_INFO(dev)->gen >= 4 && IS_MOBILE(dev)) { intel_attach_broadcast_rgb_property(&connector->base.base); + intel_sdvo->color_range_auto = true; + } } static bool @@ -2254,7 +2278,7 @@ intel_sdvo_dvi_init(struct intel_sdvo *intel_sdvo, int device) intel_sdvo_connector_init(intel_sdvo_connector, intel_sdvo); if (intel_sdvo->is_hdmi) - intel_sdvo_add_hdmi_properties(intel_sdvo_connector); + intel_sdvo_add_hdmi_properties(intel_sdvo, intel_sdvo_connector); return true; } From b1edd6a6ecd436af33f210a5c75e0249466fd200 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Thu, 17 Jan 2013 16:31:30 +0200 Subject: [PATCH 022/101] drm/edid: Add drm_rgb_quant_range_selectable() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit drm_rgb_quant_range_selectable() will report whether the monitor claims to support for RGB quantization range selection. The information can be found in the CEA Video capability block. v2: s/quantzation/quantization/ in the comment Reviewed-by: Paulo Zanoni Signed-off-by: Ville Syrjälä Acked-by: David Airlie Signed-off-by: Daniel Vetter --- drivers/gpu/drm/drm_edid.c | 33 +++++++++++++++++++++++++++++++++ include/drm/drm_crtc.h | 1 + 2 files changed, 34 insertions(+) diff --git a/drivers/gpu/drm/drm_edid.c b/drivers/gpu/drm/drm_edid.c index 5a3770fbd770..a3a3b61059ff 100644 --- a/drivers/gpu/drm/drm_edid.c +++ b/drivers/gpu/drm/drm_edid.c @@ -1483,9 +1483,11 @@ add_detailed_modes(struct drm_connector *connector, struct edid *edid, #define VIDEO_BLOCK 0x02 #define VENDOR_BLOCK 0x03 #define SPEAKER_BLOCK 0x04 +#define VIDEO_CAPABILITY_BLOCK 0x07 #define EDID_BASIC_AUDIO (1 << 6) #define EDID_CEA_YCRCB444 (1 << 5) #define EDID_CEA_YCRCB422 (1 << 4) +#define EDID_CEA_VCDB_QS (1 << 6) /** * Search EDID for CEA extension block. @@ -1901,6 +1903,37 @@ end: } EXPORT_SYMBOL(drm_detect_monitor_audio); +/** + * drm_rgb_quant_range_selectable - is RGB quantization range selectable? + * + * Check whether the monitor reports the RGB quantization range selection + * as supported. The AVI infoframe can then be used to inform the monitor + * which quantization range (full or limited) is used. + */ +bool drm_rgb_quant_range_selectable(struct edid *edid) +{ + u8 *edid_ext; + int i, start, end; + + edid_ext = drm_find_cea_extension(edid); + if (!edid_ext) + return false; + + if (cea_db_offsets(edid_ext, &start, &end)) + return false; + + for_each_cea_db(edid_ext, i, start, end) { + if (cea_db_tag(&edid_ext[i]) == VIDEO_CAPABILITY_BLOCK && + cea_db_payload_len(&edid_ext[i]) == 2) { + DRM_DEBUG_KMS("CEA VCDB 0x%02x\n", edid_ext[i + 2]); + return edid_ext[i + 2] & EDID_CEA_VCDB_QS; + } + } + + return false; +} +EXPORT_SYMBOL(drm_rgb_quant_range_selectable); + /** * drm_add_display_info - pull display info out if present * @edid: EDID data diff --git a/include/drm/drm_crtc.h b/include/drm/drm_crtc.h index 00d78b5161c0..30892dc9376e 100644 --- a/include/drm/drm_crtc.h +++ b/include/drm/drm_crtc.h @@ -1033,6 +1033,7 @@ extern u8 *drm_find_cea_extension(struct edid *edid); extern u8 drm_match_cea_mode(struct drm_display_mode *to_match); extern bool drm_detect_hdmi_monitor(struct edid *edid); extern bool drm_detect_monitor_audio(struct edid *edid); +extern bool drm_rgb_quant_range_selectable(struct edid *edid); extern int drm_mode_page_flip_ioctl(struct drm_device *dev, void *data, struct drm_file *file_priv); extern struct drm_display_mode *drm_cvt_mode(struct drm_device *dev, From abedc077b45eff0b5a8630af8431ad5d59213582 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Thu, 17 Jan 2013 16:31:31 +0200 Subject: [PATCH 023/101] drm/i915: Provide the quantization range in the AVI infoframe MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The AVI infoframe is able to inform the display whether the source is sending full or limited range RGB data. As per CEA-861 [1] we must first check whether the display reports the quantization range as selectable, and if so we can set the approriate bits in the AVI inforframe. [1] CEA-861-E - 6.4 Format of Version 2 AVI InfoFrame v2: Give the Q bits better names, add spec chapter information Reviewed-by: Paulo Zanoni Signed-off-by: Ville Syrjälä Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_drv.h | 4 ++++ drivers/gpu/drm/i915/intel_hdmi.c | 11 +++++++++++ drivers/gpu/drm/i915/intel_sdvo.c | 16 ++++++++++++++-- 3 files changed, 29 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index 1a698c6f16e7..aeff0d1067ad 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -289,6 +289,9 @@ struct cxsr_latency { #define DIP_LEN_AVI 13 #define DIP_AVI_PR_1 0 #define DIP_AVI_PR_2 1 +#define DIP_AVI_RGB_QUANT_RANGE_DEFAULT (0 << 2) +#define DIP_AVI_RGB_QUANT_RANGE_LIMITED (1 << 2) +#define DIP_AVI_RGB_QUANT_RANGE_FULL (2 << 2) #define DIP_TYPE_SPD 0x83 #define DIP_VERSION_SPD 0x1 @@ -347,6 +350,7 @@ struct intel_hdmi { bool has_hdmi_sink; bool has_audio; enum hdmi_force_audio force_audio; + bool rgb_quant_range_selectable; void (*write_infoframe)(struct drm_encoder *encoder, struct dip_infoframe *frame); void (*set_infoframes)(struct drm_encoder *encoder, diff --git a/drivers/gpu/drm/i915/intel_hdmi.c b/drivers/gpu/drm/i915/intel_hdmi.c index db67be66639b..d53b73131b0e 100644 --- a/drivers/gpu/drm/i915/intel_hdmi.c +++ b/drivers/gpu/drm/i915/intel_hdmi.c @@ -331,6 +331,7 @@ static void intel_set_infoframe(struct drm_encoder *encoder, static void intel_hdmi_set_avi_infoframe(struct drm_encoder *encoder, struct drm_display_mode *adjusted_mode) { + struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(encoder); struct dip_infoframe avi_if = { .type = DIP_TYPE_AVI, .ver = DIP_VERSION_AVI, @@ -340,6 +341,13 @@ static void intel_hdmi_set_avi_infoframe(struct drm_encoder *encoder, if (adjusted_mode->flags & DRM_MODE_FLAG_DBLCLK) avi_if.body.avi.YQ_CN_PR |= DIP_AVI_PR_2; + if (intel_hdmi->rgb_quant_range_selectable) { + if (adjusted_mode->private_flags & INTEL_MODE_LIMITED_COLOR_RANGE) + avi_if.body.avi.ITC_EC_Q_SC |= DIP_AVI_RGB_QUANT_RANGE_LIMITED; + else + avi_if.body.avi.ITC_EC_Q_SC |= DIP_AVI_RGB_QUANT_RANGE_FULL; + } + avi_if.body.avi.VIC = drm_mode_cea_vic(adjusted_mode); intel_set_infoframe(encoder, &avi_if); @@ -825,6 +833,7 @@ intel_hdmi_detect(struct drm_connector *connector, bool force) intel_hdmi->has_hdmi_sink = false; intel_hdmi->has_audio = false; + intel_hdmi->rgb_quant_range_selectable = false; edid = drm_get_edid(connector, intel_gmbus_get_adapter(dev_priv, intel_hdmi->ddc_bus)); @@ -836,6 +845,8 @@ intel_hdmi_detect(struct drm_connector *connector, bool force) intel_hdmi->has_hdmi_sink = drm_detect_hdmi_monitor(edid); intel_hdmi->has_audio = drm_detect_monitor_audio(edid); + intel_hdmi->rgb_quant_range_selectable = + drm_rgb_quant_range_selectable(edid); } kfree(edid); } diff --git a/drivers/gpu/drm/i915/intel_sdvo.c b/drivers/gpu/drm/i915/intel_sdvo.c index 3e34a3592e32..f01063a2323a 100644 --- a/drivers/gpu/drm/i915/intel_sdvo.c +++ b/drivers/gpu/drm/i915/intel_sdvo.c @@ -126,6 +126,7 @@ struct intel_sdvo { bool is_hdmi; bool has_hdmi_monitor; bool has_hdmi_audio; + bool rgb_quant_range_selectable; /** * This is set if we detect output of sdvo device as LVDS and @@ -947,7 +948,8 @@ static bool intel_sdvo_write_infoframe(struct intel_sdvo *intel_sdvo, &tx_rate, 1); } -static bool intel_sdvo_set_avi_infoframe(struct intel_sdvo *intel_sdvo) +static bool intel_sdvo_set_avi_infoframe(struct intel_sdvo *intel_sdvo, + const struct drm_display_mode *adjusted_mode) { struct dip_infoframe avi_if = { .type = DIP_TYPE_AVI, @@ -956,6 +958,13 @@ static bool intel_sdvo_set_avi_infoframe(struct intel_sdvo *intel_sdvo) }; uint8_t sdvo_data[4 + sizeof(avi_if.body.avi)]; + if (intel_sdvo->rgb_quant_range_selectable) { + if (adjusted_mode->private_flags & INTEL_MODE_LIMITED_COLOR_RANGE) + avi_if.body.avi.ITC_EC_Q_SC |= DIP_AVI_RGB_QUANT_RANGE_LIMITED; + else + avi_if.body.avi.ITC_EC_Q_SC |= DIP_AVI_RGB_QUANT_RANGE_FULL; + } + intel_dip_infoframe_csum(&avi_if); /* sdvo spec says that the ecc is handled by the hw, and it looks like @@ -1134,7 +1143,7 @@ static void intel_sdvo_mode_set(struct drm_encoder *encoder, intel_sdvo_set_encode(intel_sdvo, SDVO_ENCODE_HDMI); intel_sdvo_set_colorimetry(intel_sdvo, SDVO_COLORIMETRY_RGB256); - intel_sdvo_set_avi_infoframe(intel_sdvo); + intel_sdvo_set_avi_infoframe(intel_sdvo, adjusted_mode); } else intel_sdvo_set_encode(intel_sdvo, SDVO_ENCODE_DVI); @@ -1526,6 +1535,8 @@ intel_sdvo_tmds_sink_detect(struct drm_connector *connector) if (intel_sdvo->is_hdmi) { intel_sdvo->has_hdmi_monitor = drm_detect_hdmi_monitor(edid); intel_sdvo->has_hdmi_audio = drm_detect_monitor_audio(edid); + intel_sdvo->rgb_quant_range_selectable = + drm_rgb_quant_range_selectable(edid); } } else status = connector_status_disconnected; @@ -1577,6 +1588,7 @@ intel_sdvo_detect(struct drm_connector *connector, bool force) intel_sdvo->has_hdmi_monitor = false; intel_sdvo->has_hdmi_audio = false; + intel_sdvo->rgb_quant_range_selectable = false; if ((intel_sdvo_connector->output_flag & response) == 0) ret = connector_status_disconnected; From a81cc00c11ab6816fbcb7dd99a60b50e71765d25 Mon Sep 17 00:00:00 2001 From: Ben Widawsky Date: Fri, 18 Jan 2013 12:30:31 -0800 Subject: [PATCH 024/101] drm/i915: Cut out the infamous ILK w/a from AGP layer And, move it to where the rest of the logic is. There is some slight functionality changes. There was extra paranoid checks in AGP code making sure we never do idle maps on gen2 parts. That was not duplicated as the simple PCI id check should do the right thing. v2: use IS_GEN5 && IS_MOBILE check instead. For now, this is the same as IS_IRONLAKE_M but is more future proof. The workaround docs hint that more than one platform may be effected, but we've never seen such a platform in the wild. (Rodrigo, Daniel) Reviewed-by: Rodrigo Vivi (v1) Cc: Dave Airlie Signed-off-by: Ben Widawsky Signed-off-by: Daniel Vetter --- drivers/char/agp/intel-gtt.c | 27 --------------------------- drivers/gpu/drm/i915/i915_drv.h | 2 ++ drivers/gpu/drm/i915/i915_gem_gtt.c | 24 +++++++++++++++++++++--- include/drm/intel-gtt.h | 2 -- 4 files changed, 23 insertions(+), 32 deletions(-) diff --git a/drivers/char/agp/intel-gtt.c b/drivers/char/agp/intel-gtt.c index c8d9dcb15db0..12c31026eb56 100644 --- a/drivers/char/agp/intel-gtt.c +++ b/drivers/char/agp/intel-gtt.c @@ -840,9 +840,6 @@ static int intel_fake_agp_insert_entries(struct agp_memory *mem, { int ret = -EINVAL; - if (intel_private.base.do_idle_maps) - return -ENODEV; - if (intel_private.clear_fake_agp) { int start = intel_private.base.stolen_size / PAGE_SIZE; int end = intel_private.base.gtt_mappable_entries; @@ -907,9 +904,6 @@ static int intel_fake_agp_remove_entries(struct agp_memory *mem, if (mem->page_count == 0) return 0; - if (intel_private.base.do_idle_maps) - return -ENODEV; - intel_gtt_clear_range(pg_start, mem->page_count); if (intel_private.base.needs_dmar) { @@ -1069,24 +1063,6 @@ static void i965_write_entry(dma_addr_t addr, writel(addr | pte_flags, intel_private.gtt + entry); } -/* Certain Gen5 chipsets require require idling the GPU before - * unmapping anything from the GTT when VT-d is enabled. - */ -static inline int needs_idle_maps(void) -{ -#ifdef CONFIG_INTEL_IOMMU - const unsigned short gpu_devid = intel_private.pcidev->device; - - /* Query intel_iommu to see if we need the workaround. Presumably that - * was loaded first. - */ - if ((gpu_devid == PCI_DEVICE_ID_INTEL_IRONLAKE_M_HB || - gpu_devid == PCI_DEVICE_ID_INTEL_IRONLAKE_M_IG) && - intel_iommu_gfx_mapped) - return 1; -#endif - return 0; -} static int i9xx_setup(void) { @@ -1115,9 +1091,6 @@ static int i9xx_setup(void) break; } - if (needs_idle_maps()) - intel_private.base.do_idle_maps = 1; - intel_i9xx_setup_flush(); return 0; diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 0a2a18b8a075..1fe802f4df13 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -381,6 +381,8 @@ struct i915_gtt { /** "Graphics Stolen Memory" holds the global PTEs */ void __iomem *gsm; + + bool do_idle_maps; }; #define I915_PPGTT_PD_ENTRIES 512 diff --git a/drivers/gpu/drm/i915/i915_gem_gtt.c b/drivers/gpu/drm/i915/i915_gem_gtt.c index 0f0db02c1e56..84c521fd11a2 100644 --- a/drivers/gpu/drm/i915/i915_gem_gtt.c +++ b/drivers/gpu/drm/i915/i915_gem_gtt.c @@ -338,11 +338,27 @@ void i915_gem_init_ppgtt(struct drm_device *dev) } } +extern int intel_iommu_gfx_mapped; +/* Certain Gen5 chipsets require require idling the GPU before + * unmapping anything from the GTT when VT-d is enabled. + */ +static inline bool needs_idle_maps(struct drm_device *dev) +{ +#ifdef CONFIG_INTEL_IOMMU + /* Query intel_iommu to see if we need the workaround. Presumably that + * was loaded first. + */ + if (IS_GEN5(dev) && IS_MOBILE(dev) && intel_iommu_gfx_mapped) + return true; +#endif + return false; +} + static bool do_idling(struct drm_i915_private *dev_priv) { bool ret = dev_priv->mm.interruptible; - if (unlikely(dev_priv->mm.gtt->do_idle_maps)) { + if (unlikely(dev_priv->gtt.do_idle_maps)) { dev_priv->mm.interruptible = false; if (i915_gpu_idle(dev_priv->dev)) { DRM_ERROR("Couldn't idle GPU\n"); @@ -356,11 +372,10 @@ static bool do_idling(struct drm_i915_private *dev_priv) static void undo_idling(struct drm_i915_private *dev_priv, bool interruptible) { - if (unlikely(dev_priv->mm.gtt->do_idle_maps)) + if (unlikely(dev_priv->gtt.do_idle_maps)) dev_priv->mm.interruptible = interruptible; } - static void i915_ggtt_clear_range(struct drm_device *dev, unsigned first_entry, unsigned num_entries) @@ -709,6 +724,9 @@ int i915_gem_gtt_init(struct drm_device *dev) intel_gmch_remove(); return -ENODEV; } + + dev_priv->gtt.do_idle_maps = needs_idle_maps(dev); + return 0; } diff --git a/include/drm/intel-gtt.h b/include/drm/intel-gtt.h index 3e3a166a2690..1747aa095f41 100644 --- a/include/drm/intel-gtt.h +++ b/include/drm/intel-gtt.h @@ -13,8 +13,6 @@ struct intel_gtt { unsigned int gtt_mappable_entries; /* Whether i915 needs to use the dmar apis or not. */ unsigned int needs_dmar : 1; - /* Whether we idle the gpu before mapping/unmapping */ - unsigned int do_idle_maps : 1; /* Share the scratch page dma with ppgtts. */ dma_addr_t scratch_page_dma; struct page *scratch_page; From 9c61a32d31a55c8c6e590d83ae5645e14fde09f2 Mon Sep 17 00:00:00 2001 From: Ben Widawsky Date: Fri, 18 Jan 2013 12:30:32 -0800 Subject: [PATCH 025/101] drm/i915: Remove scratch page from shared We already had a mapping in both (minus the phys_addr in AGP). Reviewed-by: Rodrigo Vivi Signed-off-by: Ben Widawsky Signed-off-by: Daniel Vetter --- drivers/char/agp/intel-gtt.c | 9 +++++---- drivers/gpu/drm/i915/i915_drv.h | 2 ++ drivers/gpu/drm/i915/i915_gem_gtt.c | 16 ++++++++-------- include/drm/intel-gtt.h | 3 --- 4 files changed, 15 insertions(+), 15 deletions(-) diff --git a/drivers/char/agp/intel-gtt.c b/drivers/char/agp/intel-gtt.c index 12c31026eb56..7fcee5c2e986 100644 --- a/drivers/char/agp/intel-gtt.c +++ b/drivers/char/agp/intel-gtt.c @@ -75,6 +75,7 @@ static struct _intel_private { struct resource ifp_resource; int resource_valid; struct page *scratch_page; + phys_addr_t scratch_page_dma; int refcount; } intel_private; @@ -297,9 +298,9 @@ static int intel_gtt_setup_scratch_page(void) if (pci_dma_mapping_error(intel_private.pcidev, dma_addr)) return -EINVAL; - intel_private.base.scratch_page_dma = dma_addr; + intel_private.scratch_page_dma = dma_addr; } else - intel_private.base.scratch_page_dma = page_to_phys(page); + intel_private.scratch_page_dma = page_to_phys(page); intel_private.scratch_page = page; @@ -546,7 +547,7 @@ static unsigned int intel_gtt_mappable_entries(void) static void intel_gtt_teardown_scratch_page(void) { set_pages_wb(intel_private.scratch_page, 1); - pci_unmap_page(intel_private.pcidev, intel_private.base.scratch_page_dma, + pci_unmap_page(intel_private.pcidev, intel_private.scratch_page_dma, PAGE_SIZE, PCI_DMA_BIDIRECTIONAL); put_page(intel_private.scratch_page); __free_page(intel_private.scratch_page); @@ -891,7 +892,7 @@ void intel_gtt_clear_range(unsigned int first_entry, unsigned int num_entries) unsigned int i; for (i = first_entry; i < (first_entry + num_entries); i++) { - intel_private.driver->write_entry(intel_private.base.scratch_page_dma, + intel_private.driver->write_entry(intel_private.scratch_page_dma, i, 0); } readl(intel_private.gtt+i-1); diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 1fe802f4df13..3189034deeb8 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -383,6 +383,8 @@ struct i915_gtt { void __iomem *gsm; bool do_idle_maps; + dma_addr_t scratch_page_dma; + struct page *scratch_page; }; #define I915_PPGTT_PD_ENTRIES 512 diff --git a/drivers/gpu/drm/i915/i915_gem_gtt.c b/drivers/gpu/drm/i915/i915_gem_gtt.c index 84c521fd11a2..3c1f66ebc245 100644 --- a/drivers/gpu/drm/i915/i915_gem_gtt.c +++ b/drivers/gpu/drm/i915/i915_gem_gtt.c @@ -162,7 +162,7 @@ int i915_gem_init_aliasing_ppgtt(struct drm_device *dev) } } - ppgtt->scratch_page_dma_addr = dev_priv->mm.gtt->scratch_page_dma; + ppgtt->scratch_page_dma_addr = dev_priv->gtt.scratch_page_dma; i915_ppgtt_clear_range(ppgtt, 0, ppgtt->num_pd_entries*I915_PPGTT_PT_ENTRIES); @@ -396,7 +396,7 @@ static void i915_ggtt_clear_range(struct drm_device *dev, first_entry, num_entries, max_entries)) num_entries = max_entries; - scratch_pte = pte_encode(dev, dev_priv->mm.gtt->scratch_page_dma, I915_CACHE_LLC); + scratch_pte = pte_encode(dev, dev_priv->gtt.scratch_page_dma, I915_CACHE_LLC); for (i = 0; i < num_entries; i++) iowrite32(scratch_pte, >t_base[i]); readl(gtt_base); @@ -659,8 +659,8 @@ static int setup_scratch_page(struct drm_device *dev) #else dma_addr = page_to_phys(page); #endif - dev_priv->mm.gtt->scratch_page = page; - dev_priv->mm.gtt->scratch_page_dma = dma_addr; + dev_priv->gtt.scratch_page = page; + dev_priv->gtt.scratch_page_dma = dma_addr; return 0; } @@ -668,11 +668,11 @@ static int setup_scratch_page(struct drm_device *dev) static void teardown_scratch_page(struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; - set_pages_wb(dev_priv->mm.gtt->scratch_page, 1); - pci_unmap_page(dev->pdev, dev_priv->mm.gtt->scratch_page_dma, + set_pages_wb(dev_priv->gtt.scratch_page, 1); + pci_unmap_page(dev->pdev, dev_priv->gtt.scratch_page_dma, PAGE_SIZE, PCI_DMA_BIDIRECTIONAL); - put_page(dev_priv->mm.gtt->scratch_page); - __free_page(dev_priv->mm.gtt->scratch_page); + put_page(dev_priv->gtt.scratch_page); + __free_page(dev_priv->gtt.scratch_page); } static inline unsigned int gen6_get_total_gtt_size(u16 snb_gmch_ctl) diff --git a/include/drm/intel-gtt.h b/include/drm/intel-gtt.h index 1747aa095f41..c787ee4c4c07 100644 --- a/include/drm/intel-gtt.h +++ b/include/drm/intel-gtt.h @@ -13,9 +13,6 @@ struct intel_gtt { unsigned int gtt_mappable_entries; /* Whether i915 needs to use the dmar apis or not. */ unsigned int needs_dmar : 1; - /* Share the scratch page dma with ppgtts. */ - dma_addr_t scratch_page_dma; - struct page *scratch_page; /* needed for ioremap in drm/i915 */ phys_addr_t gma_bus_addr; } *intel_gtt_get(void); From 8d2e630899165d413ae8a2adc36846ac0b71bada Mon Sep 17 00:00:00 2001 From: Ben Widawsky Date: Fri, 18 Jan 2013 12:30:33 -0800 Subject: [PATCH 026/101] drm/i915: Needs_dmar, not The reasoning behind our code taking two paths depending upon whether or not we may have been configured for IOMMU isn't clear to me. It should always be safe to use the pci mapping functions as they are designed to abstract the decision we were handling in i915. Aside from simpler code, removing another member for the intel_gtt struct is a nice motivation. I ran this by Chris, and he wasn't concerned about the extra kzalloc, and memory references vs. page_to_phys calculation in the case without IOMMU. v2: Update commit message v3: Remove needs_dmar addition from Zhenyu upstream This reverts (and then other stuff) commit 20652097dadd9a7fb4d652f25466299974bc78f9 Author: Zhenyu Wang Date: Thu Dec 13 23:47:47 2012 +0800 drm/i915: Fix missed needs_dmar setting Reviewed-by: Rodrigo Vivi (v2) Cc: Zhenyu Wang Signed-off-by: Ben Widawsky [danvet: Squash in follow-up fix to remove the bogus hunk which deleted the dma_mask configuration for gen6+.] Signed-off-by: Daniel Vetter --- drivers/char/agp/intel-gtt.c | 10 ++++--- drivers/gpu/drm/i915/i915_gem_gtt.c | 45 ++++++++++------------------- include/drm/intel-gtt.h | 2 -- 3 files changed, 22 insertions(+), 35 deletions(-) diff --git a/drivers/char/agp/intel-gtt.c b/drivers/char/agp/intel-gtt.c index 7fcee5c2e986..b45241479a56 100644 --- a/drivers/char/agp/intel-gtt.c +++ b/drivers/char/agp/intel-gtt.c @@ -77,6 +77,8 @@ static struct _intel_private { struct page *scratch_page; phys_addr_t scratch_page_dma; int refcount; + /* Whether i915 needs to use the dmar apis or not. */ + unsigned int needs_dmar : 1; } intel_private; #define INTEL_GTT_GEN intel_private.driver->gen @@ -292,7 +294,7 @@ static int intel_gtt_setup_scratch_page(void) get_page(page); set_pages_uc(page, 1); - if (intel_private.base.needs_dmar) { + if (intel_private.needs_dmar) { dma_addr = pci_map_page(intel_private.pcidev, page, 0, PAGE_SIZE, PCI_DMA_BIDIRECTIONAL); if (pci_dma_mapping_error(intel_private.pcidev, dma_addr)) @@ -608,7 +610,7 @@ static int intel_gtt_init(void) intel_private.base.stolen_size = intel_gtt_stolen_size(); - intel_private.base.needs_dmar = USE_PCI_DMA_API && INTEL_GTT_GEN > 2; + intel_private.needs_dmar = USE_PCI_DMA_API && INTEL_GTT_GEN > 2; ret = intel_gtt_setup_scratch_page(); if (ret != 0) { @@ -866,7 +868,7 @@ static int intel_fake_agp_insert_entries(struct agp_memory *mem, if (!mem->is_flushed) global_cache_flush(); - if (intel_private.base.needs_dmar) { + if (intel_private.needs_dmar) { struct sg_table st; ret = intel_gtt_map_memory(mem->pages, mem->page_count, &st); @@ -907,7 +909,7 @@ static int intel_fake_agp_remove_entries(struct agp_memory *mem, intel_gtt_clear_range(pg_start, mem->page_count); - if (intel_private.base.needs_dmar) { + if (intel_private.needs_dmar) { intel_gtt_unmap_memory(mem->sg_list, mem->num_sg); mem->sg_list = NULL; mem->num_sg = 0; diff --git a/drivers/gpu/drm/i915/i915_gem_gtt.c b/drivers/gpu/drm/i915/i915_gem_gtt.c index 3c1f66ebc245..a0ba4a9e53c7 100644 --- a/drivers/gpu/drm/i915/i915_gem_gtt.c +++ b/drivers/gpu/drm/i915/i915_gem_gtt.c @@ -138,28 +138,23 @@ int i915_gem_init_aliasing_ppgtt(struct drm_device *dev) goto err_pt_alloc; } - if (dev_priv->mm.gtt->needs_dmar) { - ppgtt->pt_dma_addr = kzalloc(sizeof(dma_addr_t) - *ppgtt->num_pd_entries, - GFP_KERNEL); - if (!ppgtt->pt_dma_addr) - goto err_pt_alloc; + ppgtt->pt_dma_addr = kzalloc(sizeof(dma_addr_t) *ppgtt->num_pd_entries, + GFP_KERNEL); + if (!ppgtt->pt_dma_addr) + goto err_pt_alloc; - for (i = 0; i < ppgtt->num_pd_entries; i++) { - dma_addr_t pt_addr; + for (i = 0; i < ppgtt->num_pd_entries; i++) { + dma_addr_t pt_addr; - pt_addr = pci_map_page(dev->pdev, ppgtt->pt_pages[i], - 0, 4096, - PCI_DMA_BIDIRECTIONAL); + pt_addr = pci_map_page(dev->pdev, ppgtt->pt_pages[i], 0, 4096, + PCI_DMA_BIDIRECTIONAL); - if (pci_dma_mapping_error(dev->pdev, - pt_addr)) { - ret = -EIO; - goto err_pd_pin; + if (pci_dma_mapping_error(dev->pdev, pt_addr)) { + ret = -EIO; + goto err_pd_pin; - } - ppgtt->pt_dma_addr[i] = pt_addr; } + ppgtt->pt_dma_addr[i] = pt_addr; } ppgtt->scratch_page_dma_addr = dev_priv->gtt.scratch_page_dma; @@ -294,11 +289,7 @@ void i915_gem_init_ppgtt(struct drm_device *dev) for (i = 0; i < ppgtt->num_pd_entries; i++) { dma_addr_t pt_addr; - if (dev_priv->mm.gtt->needs_dmar) - pt_addr = ppgtt->pt_dma_addr[i]; - else - pt_addr = page_to_phys(ppgtt->pt_pages[i]); - + pt_addr = ppgtt->pt_dma_addr[i]; pd_entry = GEN6_PDE_ADDR_ENCODE(pt_addr); pd_entry |= GEN6_PDE_VALID; @@ -730,16 +721,12 @@ int i915_gem_gtt_init(struct drm_device *dev) return 0; } - dev_priv->mm.gtt = kzalloc(sizeof(*dev_priv->mm.gtt), GFP_KERNEL); - if (!dev_priv->mm.gtt) - return -ENOMEM; - if (!pci_set_dma_mask(dev->pdev, DMA_BIT_MASK(40))) pci_set_consistent_dma_mask(dev->pdev, DMA_BIT_MASK(40)); -#ifdef CONFIG_INTEL_IOMMU - dev_priv->mm.gtt->needs_dmar = 1; -#endif + dev_priv->mm.gtt = kzalloc(sizeof(*dev_priv->mm.gtt), GFP_KERNEL); + if (!dev_priv->mm.gtt) + return -ENOMEM; /* For GEN6+ the PTEs for the ggtt live at 2MB + BAR0 */ gtt_bus_addr = pci_resource_start(dev->pdev, 0) + (2<<20); diff --git a/include/drm/intel-gtt.h b/include/drm/intel-gtt.h index c787ee4c4c07..984105cddc57 100644 --- a/include/drm/intel-gtt.h +++ b/include/drm/intel-gtt.h @@ -11,8 +11,6 @@ struct intel_gtt { /* Part of the gtt that is mappable by the cpu, for those chips where * this is not the full gtt. */ unsigned int gtt_mappable_entries; - /* Whether i915 needs to use the dmar apis or not. */ - unsigned int needs_dmar : 1; /* needed for ioremap in drm/i915 */ phys_addr_t gma_bus_addr; } *intel_gtt_get(void); From e5c653777986b40e2986d2c918847fddbcba3a34 Mon Sep 17 00:00:00 2001 From: Ben Widawsky Date: Fri, 18 Jan 2013 12:30:34 -0800 Subject: [PATCH 027/101] agp/intel: Add gma_bus_addr It is no longer used in the i915 code, so isolate it from the shared struct. This was originally part of: commit 0e275518f325418d559c05327775bff894b237f7 Author: Ben Widawsky Date: Mon Jan 14 13:35:33 2013 -0800 agp/intel: decouple more of the agp-i915 sharing Reviewed-by: Rodrigo Vivi Signed-off-by: Ben Widawsky That commit had some other hunks which can't be used due to issues Daniel found in previous commits. Signed-off-by: Ben Widawsky [danvet: drop squash notice from the commit since it's imo ok to keep this one separate.] Signed-off-by: Daniel Vetter --- drivers/char/agp/intel-gtt.c | 5 +++-- include/drm/intel-gtt.h | 2 -- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/drivers/char/agp/intel-gtt.c b/drivers/char/agp/intel-gtt.c index b45241479a56..ff5f3483e8ea 100644 --- a/drivers/char/agp/intel-gtt.c +++ b/drivers/char/agp/intel-gtt.c @@ -79,6 +79,7 @@ static struct _intel_private { int refcount; /* Whether i915 needs to use the dmar apis or not. */ unsigned int needs_dmar : 1; + phys_addr_t gma_bus_addr; } intel_private; #define INTEL_GTT_GEN intel_private.driver->gen @@ -625,7 +626,7 @@ static int intel_gtt_init(void) pci_read_config_dword(intel_private.pcidev, I915_GMADDR, &gma_addr); - intel_private.base.gma_bus_addr = (gma_addr & PCI_BASE_ADDRESS_MEM_MASK); + intel_private.gma_bus_addr = (gma_addr & PCI_BASE_ADDRESS_MEM_MASK); return 0; } @@ -781,7 +782,7 @@ static int intel_fake_agp_configure(void) return -EIO; intel_private.clear_fake_agp = true; - agp_bridge->gart_bus_addr = intel_private.base.gma_bus_addr; + agp_bridge->gart_bus_addr = intel_private.gma_bus_addr; return 0; } diff --git a/include/drm/intel-gtt.h b/include/drm/intel-gtt.h index 984105cddc57..769b6c79097e 100644 --- a/include/drm/intel-gtt.h +++ b/include/drm/intel-gtt.h @@ -11,8 +11,6 @@ struct intel_gtt { /* Part of the gtt that is mappable by the cpu, for those chips where * this is not the full gtt. */ unsigned int gtt_mappable_entries; - /* needed for ioremap in drm/i915 */ - phys_addr_t gma_bus_addr; } *intel_gtt_get(void); int intel_gmch_probe(struct pci_dev *bridge_pdev, struct pci_dev *gpu_pdev, From 4b5aed62121eddfc47fd8f2739ca6b802b97390e Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Wed, 14 Nov 2012 17:14:03 +0100 Subject: [PATCH 028/101] drm/i915: move dev_priv->mm out of line Tha one is really big, since it contains tons of comments explaining how things work. Which is nice ;-) Reviewed-by: Damien Lespiau Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_drv.h | 202 ++++++++++++++++---------------- 1 file changed, 102 insertions(+), 100 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 3189034deeb8..ea3226852ea8 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -665,6 +665,107 @@ struct intel_l3_parity { struct work_struct error_work; }; +struct i915_gem_mm { + /** Bridge to intel-gtt-ko */ + struct intel_gtt *gtt; + /** Memory allocator for GTT stolen memory */ + struct drm_mm stolen; + /** Memory allocator for GTT */ + struct drm_mm gtt_space; + /** List of all objects in gtt_space. Used to restore gtt + * mappings on resume */ + struct list_head bound_list; + /** + * List of objects which are not bound to the GTT (thus + * are idle and not used by the GPU) but still have + * (presumably uncached) pages still attached. + */ + struct list_head unbound_list; + + /** Usable portion of the GTT for GEM */ + unsigned long stolen_base; /* limited to low memory (32-bit) */ + + int gtt_mtrr; + + /** PPGTT used for aliasing the PPGTT with the GTT */ + struct i915_hw_ppgtt *aliasing_ppgtt; + + struct shrinker inactive_shrinker; + bool shrinker_no_lock_stealing; + + /** + * List of objects currently involved in rendering. + * + * Includes buffers having the contents of their GPU caches + * flushed, not necessarily primitives. last_rendering_seqno + * represents when the rendering involved will be completed. + * + * A reference is held on the buffer while on this list. + */ + struct list_head active_list; + + /** + * LRU list of objects which are not in the ringbuffer and + * are ready to unbind, but are still in the GTT. + * + * last_rendering_seqno is 0 while an object is in this list. + * + * A reference is not held on the buffer while on this list, + * as merely being GTT-bound shouldn't prevent its being + * freed, and we'll pull it off the list in the free path. + */ + struct list_head inactive_list; + + /** LRU list of objects with fence regs on them. */ + struct list_head fence_list; + + /** + * We leave the user IRQ off as much as possible, + * but this means that requests will finish and never + * be retired once the system goes idle. Set a timer to + * fire periodically while the ring is running. When it + * fires, go retire requests. + */ + struct delayed_work retire_work; + + /** + * Are we in a non-interruptible section of code like + * modesetting? + */ + bool interruptible; + + /** + * Flag if the X Server, and thus DRM, is not currently in + * control of the device. + * + * This is set between LeaveVT and EnterVT. It needs to be + * replaced with a semaphore. It also needs to be + * transitioned away from for kernel modesetting. + */ + int suspended; + + /** + * Flag if the hardware appears to be wedged. + * + * This is set when attempts to idle the device timeout. + * It prevents command submission from occurring and makes + * every pending request fail + */ + atomic_t wedged; + + /** Bit 6 swizzling required for X tiling */ + uint32_t bit_6_swizzle_x; + /** Bit 6 swizzling required for Y tiling */ + uint32_t bit_6_swizzle_y; + + /* storage for physical objects */ + struct drm_i915_gem_phys_object *phys_objs[I915_MAX_PHYS_OBJECT]; + + /* accounting, useful for userland debugging */ + size_t object_memory; + u32 object_count; +}; + typedef struct drm_i915_private { struct drm_device *dev; struct kmem_cache *slab; @@ -806,106 +907,7 @@ typedef struct drm_i915_private { struct i915_gtt gtt; - struct { - /** Bridge to intel-gtt-ko */ - struct intel_gtt *gtt; - /** Memory allocator for GTT stolen memory */ - struct drm_mm stolen; - /** Memory allocator for GTT */ - struct drm_mm gtt_space; - /** List of all objects in gtt_space. Used to restore gtt - * mappings on resume */ - struct list_head bound_list; - /** - * List of objects which are not bound to the GTT (thus - * are idle and not used by the GPU) but still have - * (presumably uncached) pages still attached. - */ - struct list_head unbound_list; - - /** Usable portion of the GTT for GEM */ - unsigned long stolen_base; /* limited to low memory (32-bit) */ - - int gtt_mtrr; - - /** PPGTT used for aliasing the PPGTT with the GTT */ - struct i915_hw_ppgtt *aliasing_ppgtt; - - struct shrinker inactive_shrinker; - bool shrinker_no_lock_stealing; - - /** - * List of objects currently involved in rendering. - * - * Includes buffers having the contents of their GPU caches - * flushed, not necessarily primitives. last_rendering_seqno - * represents when the rendering involved will be completed. - * - * A reference is held on the buffer while on this list. - */ - struct list_head active_list; - - /** - * LRU list of objects which are not in the ringbuffer and - * are ready to unbind, but are still in the GTT. - * - * last_rendering_seqno is 0 while an object is in this list. - * - * A reference is not held on the buffer while on this list, - * as merely being GTT-bound shouldn't prevent its being - * freed, and we'll pull it off the list in the free path. - */ - struct list_head inactive_list; - - /** LRU list of objects with fence regs on them. */ - struct list_head fence_list; - - /** - * We leave the user IRQ off as much as possible, - * but this means that requests will finish and never - * be retired once the system goes idle. Set a timer to - * fire periodically while the ring is running. When it - * fires, go retire requests. - */ - struct delayed_work retire_work; - - /** - * Are we in a non-interruptible section of code like - * modesetting? - */ - bool interruptible; - - /** - * Flag if the X Server, and thus DRM, is not currently in - * control of the device. - * - * This is set between LeaveVT and EnterVT. It needs to be - * replaced with a semaphore. It also needs to be - * transitioned away from for kernel modesetting. - */ - int suspended; - - /** - * Flag if the hardware appears to be wedged. - * - * This is set when attempts to idle the device timeout. - * It prevents command submission from occurring and makes - * every pending request fail - */ - atomic_t wedged; - - /** Bit 6 swizzling required for X tiling */ - uint32_t bit_6_swizzle_x; - /** Bit 6 swizzling required for Y tiling */ - uint32_t bit_6_swizzle_y; - - /* storage for physical objects */ - struct drm_i915_gem_phys_object *phys_objs[I915_MAX_PHYS_OBJECT]; - - /* accounting, useful for userland debugging */ - size_t object_memory; - u32 object_count; - } mm; + struct i915_gem_mm mm; /* Kernel Modesetting */ From 99584db33ba4f864777e2cfef5329ed1bf13f714 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Wed, 14 Nov 2012 17:14:04 +0100 Subject: [PATCH 029/101] drm/i915: extract hangcheck/reset/error_state state into substruct This has been sprinkled all over the place in dev_priv. I think it'd be good to also move all the code into a separate file like i915_gem_error.c, but that's for another patch. Reviewed-by: Damien Lespiau Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_debugfs.c | 10 ++--- drivers/gpu/drm/i915/i915_dma.c | 6 +-- drivers/gpu/drm/i915/i915_drv.c | 8 ++-- drivers/gpu/drm/i915/i915_drv.h | 39 +++++++++------- drivers/gpu/drm/i915/i915_gem.c | 10 ++--- drivers/gpu/drm/i915/i915_irq.c | 59 ++++++++++++++----------- drivers/gpu/drm/i915/intel_ringbuffer.c | 2 +- 7 files changed, 73 insertions(+), 61 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_debugfs.c b/drivers/gpu/drm/i915/i915_debugfs.c index 90a6fc506dd5..3b1bf4e70d94 100644 --- a/drivers/gpu/drm/i915/i915_debugfs.c +++ b/drivers/gpu/drm/i915/i915_debugfs.c @@ -814,11 +814,11 @@ static int i915_error_state_open(struct inode *inode, struct file *file) error_priv->dev = dev; - spin_lock_irqsave(&dev_priv->error_lock, flags); - error_priv->error = dev_priv->first_error; + spin_lock_irqsave(&dev_priv->gpu_error.lock, flags); + error_priv->error = dev_priv->gpu_error.first_error; if (error_priv->error) kref_get(&error_priv->error->ref); - spin_unlock_irqrestore(&dev_priv->error_lock, flags); + spin_unlock_irqrestore(&dev_priv->gpu_error.lock, flags); return single_open(file, i915_error_state, error_priv); } @@ -1727,7 +1727,7 @@ i915_ring_stop_read(struct file *filp, int len; len = snprintf(buf, sizeof(buf), - "0x%08x\n", dev_priv->stop_rings); + "0x%08x\n", dev_priv->gpu_error.stop_rings); if (len > sizeof(buf)) len = sizeof(buf); @@ -1763,7 +1763,7 @@ i915_ring_stop_write(struct file *filp, if (ret) return ret; - dev_priv->stop_rings = val; + dev_priv->gpu_error.stop_rings = val; mutex_unlock(&dev->struct_mutex); return cnt; diff --git a/drivers/gpu/drm/i915/i915_dma.c b/drivers/gpu/drm/i915/i915_dma.c index 3f70178c63ca..11c7aa80e29b 100644 --- a/drivers/gpu/drm/i915/i915_dma.c +++ b/drivers/gpu/drm/i915/i915_dma.c @@ -1605,7 +1605,7 @@ int i915_driver_load(struct drm_device *dev, unsigned long flags) pci_enable_msi(dev->pdev); spin_lock_init(&dev_priv->irq_lock); - spin_lock_init(&dev_priv->error_lock); + spin_lock_init(&dev_priv->gpu_error.lock); spin_lock_init(&dev_priv->rps.lock); mutex_init(&dev_priv->dpio_lock); @@ -1725,8 +1725,8 @@ int i915_driver_unload(struct drm_device *dev) } /* Free error state after interrupts are fully disabled. */ - del_timer_sync(&dev_priv->hangcheck_timer); - cancel_work_sync(&dev_priv->error_work); + del_timer_sync(&dev_priv->gpu_error.hangcheck_timer); + cancel_work_sync(&dev_priv->gpu_error.work); i915_destroy_error_state(dev); if (dev->pdev->msi_enabled) diff --git a/drivers/gpu/drm/i915/i915_drv.c b/drivers/gpu/drm/i915/i915_drv.c index c8cbc32fe8db..3ff8e73f4341 100644 --- a/drivers/gpu/drm/i915/i915_drv.c +++ b/drivers/gpu/drm/i915/i915_drv.c @@ -779,9 +779,9 @@ int intel_gpu_reset(struct drm_device *dev) } /* Also reset the gpu hangman. */ - if (dev_priv->stop_rings) { + if (dev_priv->gpu_error.stop_rings) { DRM_DEBUG("Simulated gpu hang, resetting stop_rings\n"); - dev_priv->stop_rings = 0; + dev_priv->gpu_error.stop_rings = 0; if (ret == -ENODEV) { DRM_ERROR("Reset not implemented, but ignoring " "error for simulated gpu hangs\n"); @@ -820,12 +820,12 @@ int i915_reset(struct drm_device *dev) i915_gem_reset(dev); ret = -ENODEV; - if (get_seconds() - dev_priv->last_gpu_reset < 5) + if (get_seconds() - dev_priv->gpu_error.last_reset < 5) DRM_ERROR("GPU hanging too fast, declaring wedged!\n"); else ret = intel_gpu_reset(dev); - dev_priv->last_gpu_reset = get_seconds(); + dev_priv->gpu_error.last_reset = get_seconds(); if (ret) { DRM_ERROR("Failed to reset chip.\n"); mutex_unlock(&dev->struct_mutex); diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index ea3226852ea8..dfe0e747c4f7 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -766,6 +766,28 @@ struct i915_gem_mm { u32 object_count; }; +struct i915_gpu_error { + /* For hangcheck timer */ +#define DRM_I915_HANGCHECK_PERIOD 1500 /* in ms */ +#define DRM_I915_HANGCHECK_JIFFIES msecs_to_jiffies(DRM_I915_HANGCHECK_PERIOD) + struct timer_list hangcheck_timer; + int hangcheck_count; + uint32_t last_acthd[I915_NUM_RINGS]; + uint32_t prev_instdone[I915_NUM_INSTDONE_REG]; + + /* For reset and error_state handling. */ + spinlock_t lock; + /* Protected by the above dev->gpu_error.lock. */ + struct drm_i915_error_state *first_error; + struct work_struct work; + struct completion completion; + + unsigned long last_reset; + + /* For gpu hang simulation. */ + unsigned int stop_rings; +}; + typedef struct drm_i915_private { struct drm_device *dev; struct kmem_cache *slab; @@ -829,16 +851,6 @@ typedef struct drm_i915_private { int num_pipe; int num_pch_pll; - /* For hangcheck timer */ -#define DRM_I915_HANGCHECK_PERIOD 1500 /* in ms */ -#define DRM_I915_HANGCHECK_JIFFIES msecs_to_jiffies(DRM_I915_HANGCHECK_PERIOD) - struct timer_list hangcheck_timer; - int hangcheck_count; - uint32_t last_acthd[I915_NUM_RINGS]; - uint32_t prev_instdone[I915_NUM_INSTDONE_REG]; - - unsigned int stop_rings; - unsigned long cfb_size; unsigned int cfb_fb; enum plane cfb_plane; @@ -886,11 +898,6 @@ typedef struct drm_i915_private { unsigned int fsb_freq, mem_freq, is_ddr3; - spinlock_t error_lock; - /* Protected by dev->error_lock. */ - struct drm_i915_error_state *first_error; - struct work_struct error_work; - struct completion error_completion; struct workqueue_struct *wq; /* Display functions */ @@ -949,7 +956,7 @@ typedef struct drm_i915_private { struct drm_mm_node *compressed_fb; struct drm_mm_node *compressed_llb; - unsigned long last_gpu_reset; + struct i915_gpu_error gpu_error; /* list of fbdev register on this device */ struct intel_fbdev *fbdev; diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index e4132ffb7609..95e022e7a26e 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -90,7 +90,7 @@ static int i915_gem_wait_for_error(struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; - struct completion *x = &dev_priv->error_completion; + struct completion *x = &dev_priv->gpu_error.completion; unsigned long flags; int ret; @@ -943,7 +943,7 @@ i915_gem_check_wedge(struct drm_i915_private *dev_priv, bool interruptible) { if (atomic_read(&dev_priv->mm.wedged)) { - struct completion *x = &dev_priv->error_completion; + struct completion *x = &dev_priv->gpu_error.completion; bool recovery_complete; unsigned long flags; @@ -2045,7 +2045,7 @@ i915_add_request(struct intel_ring_buffer *ring, if (!dev_priv->mm.suspended) { if (i915_enable_hangcheck) { - mod_timer(&dev_priv->hangcheck_timer, + mod_timer(&dev_priv->gpu_error.hangcheck_timer, round_jiffies_up(jiffies + DRM_I915_HANGCHECK_JIFFIES)); } if (was_empty) { @@ -3803,7 +3803,7 @@ i915_gem_idle(struct drm_device *dev) * And not confound mm.suspended! */ dev_priv->mm.suspended = 1; - del_timer_sync(&dev_priv->hangcheck_timer); + del_timer_sync(&dev_priv->gpu_error.hangcheck_timer); i915_kernel_lost_context(dev); i915_gem_cleanup_ringbuffer(dev); @@ -4064,7 +4064,7 @@ i915_gem_load(struct drm_device *dev) INIT_LIST_HEAD(&dev_priv->fence_regs[i].lru_list); INIT_DELAYED_WORK(&dev_priv->mm.retire_work, i915_gem_retire_work_handler); - init_completion(&dev_priv->error_completion); + init_completion(&dev_priv->gpu_error.completion); /* On GEN3 we really need to make sure the ARB C3 LP bit is set */ if (IS_GEN3(dev)) { diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c index cc49a6ddc052..c768ebdf8a27 100644 --- a/drivers/gpu/drm/i915/i915_irq.c +++ b/drivers/gpu/drm/i915/i915_irq.c @@ -356,8 +356,8 @@ static void notify_ring(struct drm_device *dev, wake_up_all(&ring->irq_queue); if (i915_enable_hangcheck) { - dev_priv->hangcheck_count = 0; - mod_timer(&dev_priv->hangcheck_timer, + dev_priv->gpu_error.hangcheck_count = 0; + mod_timer(&dev_priv->gpu_error.hangcheck_timer, round_jiffies_up(jiffies + DRM_I915_HANGCHECK_JIFFIES)); } } @@ -863,7 +863,7 @@ done: static void i915_error_work_func(struct work_struct *work) { drm_i915_private_t *dev_priv = container_of(work, drm_i915_private_t, - error_work); + gpu_error.work); struct drm_device *dev = dev_priv->dev; char *error_event[] = { "ERROR=1", NULL }; char *reset_event[] = { "RESET=1", NULL }; @@ -878,7 +878,7 @@ static void i915_error_work_func(struct work_struct *work) atomic_set(&dev_priv->mm.wedged, 0); kobject_uevent_env(&dev->primary->kdev.kobj, KOBJ_CHANGE, reset_done_event); } - complete_all(&dev_priv->error_completion); + complete_all(&dev_priv->gpu_error.completion); } } @@ -1255,9 +1255,9 @@ static void i915_capture_error_state(struct drm_device *dev) unsigned long flags; int i, pipe; - spin_lock_irqsave(&dev_priv->error_lock, flags); - error = dev_priv->first_error; - spin_unlock_irqrestore(&dev_priv->error_lock, flags); + spin_lock_irqsave(&dev_priv->gpu_error.lock, flags); + error = dev_priv->gpu_error.first_error; + spin_unlock_irqrestore(&dev_priv->gpu_error.lock, flags); if (error) return; @@ -1341,12 +1341,12 @@ static void i915_capture_error_state(struct drm_device *dev) error->overlay = intel_overlay_capture_error_state(dev); error->display = intel_display_capture_error_state(dev); - spin_lock_irqsave(&dev_priv->error_lock, flags); - if (dev_priv->first_error == NULL) { - dev_priv->first_error = error; + spin_lock_irqsave(&dev_priv->gpu_error.lock, flags); + if (dev_priv->gpu_error.first_error == NULL) { + dev_priv->gpu_error.first_error = error; error = NULL; } - spin_unlock_irqrestore(&dev_priv->error_lock, flags); + spin_unlock_irqrestore(&dev_priv->gpu_error.lock, flags); if (error) i915_error_state_free(&error->ref); @@ -1358,10 +1358,10 @@ void i915_destroy_error_state(struct drm_device *dev) struct drm_i915_error_state *error; unsigned long flags; - spin_lock_irqsave(&dev_priv->error_lock, flags); - error = dev_priv->first_error; - dev_priv->first_error = NULL; - spin_unlock_irqrestore(&dev_priv->error_lock, flags); + spin_lock_irqsave(&dev_priv->gpu_error.lock, flags); + error = dev_priv->gpu_error.first_error; + dev_priv->gpu_error.first_error = NULL; + spin_unlock_irqrestore(&dev_priv->gpu_error.lock, flags); if (error) kref_put(&error->ref, i915_error_state_free); @@ -1482,7 +1482,7 @@ void i915_handle_error(struct drm_device *dev, bool wedged) i915_report_and_clear_eir(dev); if (wedged) { - INIT_COMPLETION(dev_priv->error_completion); + INIT_COMPLETION(dev_priv->gpu_error.completion); atomic_set(&dev_priv->mm.wedged, 1); /* @@ -1492,7 +1492,7 @@ void i915_handle_error(struct drm_device *dev, bool wedged) wake_up_all(&ring->irq_queue); } - queue_work(dev_priv->wq, &dev_priv->error_work); + queue_work(dev_priv->wq, &dev_priv->gpu_error.work); } static void i915_pageflip_stall_check(struct drm_device *dev, int pipe) @@ -1723,7 +1723,7 @@ static bool i915_hangcheck_hung(struct drm_device *dev) { drm_i915_private_t *dev_priv = dev->dev_private; - if (dev_priv->hangcheck_count++ > 1) { + if (dev_priv->gpu_error.hangcheck_count++ > 1) { bool hung = true; DRM_ERROR("Hangcheck timer elapsed... GPU hung\n"); @@ -1782,25 +1782,29 @@ void i915_hangcheck_elapsed(unsigned long data) goto repeat; } - dev_priv->hangcheck_count = 0; + dev_priv->gpu_error.hangcheck_count = 0; return; } i915_get_extra_instdone(dev, instdone); - if (memcmp(dev_priv->last_acthd, acthd, sizeof(acthd)) == 0 && - memcmp(dev_priv->prev_instdone, instdone, sizeof(instdone)) == 0) { + if (memcmp(dev_priv->gpu_error.last_acthd, acthd, + sizeof(acthd)) == 0 && + memcmp(dev_priv->gpu_error.prev_instdone, instdone, + sizeof(instdone)) == 0) { if (i915_hangcheck_hung(dev)) return; } else { - dev_priv->hangcheck_count = 0; + dev_priv->gpu_error.hangcheck_count = 0; - memcpy(dev_priv->last_acthd, acthd, sizeof(acthd)); - memcpy(dev_priv->prev_instdone, instdone, sizeof(instdone)); + memcpy(dev_priv->gpu_error.last_acthd, acthd, + sizeof(acthd)); + memcpy(dev_priv->gpu_error.prev_instdone, instdone, + sizeof(instdone)); } repeat: /* Reset timer case chip hangs without another request being added */ - mod_timer(&dev_priv->hangcheck_timer, + mod_timer(&dev_priv->gpu_error.hangcheck_timer, round_jiffies_up(jiffies + DRM_I915_HANGCHECK_JIFFIES)); } @@ -2769,11 +2773,12 @@ void intel_irq_init(struct drm_device *dev) struct drm_i915_private *dev_priv = dev->dev_private; INIT_WORK(&dev_priv->hotplug_work, i915_hotplug_work_func); - INIT_WORK(&dev_priv->error_work, i915_error_work_func); + INIT_WORK(&dev_priv->gpu_error.work, i915_error_work_func); INIT_WORK(&dev_priv->rps.work, gen6_pm_rps_work); INIT_WORK(&dev_priv->l3_parity.error_work, ivybridge_parity_work); - setup_timer(&dev_priv->hangcheck_timer, i915_hangcheck_elapsed, + setup_timer(&dev_priv->gpu_error.hangcheck_timer, + i915_hangcheck_elapsed, (unsigned long) dev); pm_qos_add_request(&dev_priv->pm_qos, PM_QOS_CPU_DMA_LATENCY, PM_QOS_DEFAULT_VALUE); diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.c b/drivers/gpu/drm/i915/intel_ringbuffer.c index ce1d07487402..d6b06aa4c05c 100644 --- a/drivers/gpu/drm/i915/intel_ringbuffer.c +++ b/drivers/gpu/drm/i915/intel_ringbuffer.c @@ -1491,7 +1491,7 @@ void intel_ring_advance(struct intel_ring_buffer *ring) struct drm_i915_private *dev_priv = ring->dev->dev_private; ring->tail &= ring->size - 1; - if (dev_priv->stop_rings & intel_ring_flag(ring)) + if (dev_priv->gpu_error.stop_rings & intel_ring_flag(ring)) return; ring->write_tail(ring, ring->tail); } From 33196deddacc7790defb9a7e84659e0362d4da7a Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Wed, 14 Nov 2012 17:14:05 +0100 Subject: [PATCH 030/101] drm/i915: move wedged to the other gpu error handling stuff And to make Ben Widawsky happier, use the gpu_error instead of the entire device as the argument in some functions. Drop the outdated comment on ->wedged for now, a follow-up patch will change the semantics and add a proper comment again. Reviewed-by: Damien Lespiau Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_debugfs.c | 2 +- drivers/gpu/drm/i915/i915_drv.h | 13 +++------- drivers/gpu/drm/i915/i915_gem.c | 34 ++++++++++++------------- drivers/gpu/drm/i915/i915_irq.c | 6 ++--- drivers/gpu/drm/i915/intel_display.c | 4 +-- drivers/gpu/drm/i915/intel_ringbuffer.c | 6 +++-- 6 files changed, 30 insertions(+), 35 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_debugfs.c b/drivers/gpu/drm/i915/i915_debugfs.c index 3b1bf4e70d94..e1b7eaf60d24 100644 --- a/drivers/gpu/drm/i915/i915_debugfs.c +++ b/drivers/gpu/drm/i915/i915_debugfs.c @@ -1672,7 +1672,7 @@ i915_wedged_read(struct file *filp, len = snprintf(buf, sizeof(buf), "wedged : %d\n", - atomic_read(&dev_priv->mm.wedged)); + atomic_read(&dev_priv->gpu_error.wedged)); if (len > sizeof(buf)) len = sizeof(buf); diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index dfe0e747c4f7..62da6c7a4884 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -744,15 +744,6 @@ struct i915_gem_mm { */ int suspended; - /** - * Flag if the hardware appears to be wedged. - * - * This is set when attempts to idle the device timeout. - * It prevents command submission from occurring and makes - * every pending request fail - */ - atomic_t wedged; - /** Bit 6 swizzling required for X tiling */ uint32_t bit_6_swizzle_x; /** Bit 6 swizzling required for Y tiling */ @@ -784,6 +775,8 @@ struct i915_gpu_error { unsigned long last_reset; + atomic_t wedged; + /* For gpu hang simulation. */ unsigned int stop_rings; }; @@ -1548,7 +1541,7 @@ i915_gem_object_unpin_fence(struct drm_i915_gem_object *obj) void i915_gem_retire_requests(struct drm_device *dev); void i915_gem_retire_requests_ring(struct intel_ring_buffer *ring); -int __must_check i915_gem_check_wedge(struct drm_i915_private *dev_priv, +int __must_check i915_gem_check_wedge(struct i915_gpu_error *error, bool interruptible); void i915_gem_reset(struct drm_device *dev); diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index 95e022e7a26e..04b2f92eb456 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -87,14 +87,13 @@ static void i915_gem_info_remove_obj(struct drm_i915_private *dev_priv, } static int -i915_gem_wait_for_error(struct drm_device *dev) +i915_gem_wait_for_error(struct i915_gpu_error *error) { - struct drm_i915_private *dev_priv = dev->dev_private; - struct completion *x = &dev_priv->gpu_error.completion; + struct completion *x = &error->completion; unsigned long flags; int ret; - if (!atomic_read(&dev_priv->mm.wedged)) + if (!atomic_read(&error->wedged)) return 0; /* @@ -110,7 +109,7 @@ i915_gem_wait_for_error(struct drm_device *dev) return ret; } - if (atomic_read(&dev_priv->mm.wedged)) { + if (atomic_read(&error->wedged)) { /* GPU is hung, bump the completion count to account for * the token we just consumed so that we never hit zero and * end up waiting upon a subsequent completion event that @@ -125,9 +124,10 @@ i915_gem_wait_for_error(struct drm_device *dev) int i915_mutex_lock_interruptible(struct drm_device *dev) { + struct drm_i915_private *dev_priv = dev->dev_private; int ret; - ret = i915_gem_wait_for_error(dev); + ret = i915_gem_wait_for_error(&dev_priv->gpu_error); if (ret) return ret; @@ -939,11 +939,11 @@ unlock: } int -i915_gem_check_wedge(struct drm_i915_private *dev_priv, +i915_gem_check_wedge(struct i915_gpu_error *error, bool interruptible) { - if (atomic_read(&dev_priv->mm.wedged)) { - struct completion *x = &dev_priv->gpu_error.completion; + if (atomic_read(&error->wedged)) { + struct completion *x = &error->completion; bool recovery_complete; unsigned long flags; @@ -1025,7 +1025,7 @@ static int __wait_seqno(struct intel_ring_buffer *ring, u32 seqno, #define EXIT_COND \ (i915_seqno_passed(ring->get_seqno(ring, false), seqno) || \ - atomic_read(&dev_priv->mm.wedged)) + atomic_read(&dev_priv->gpu_error.wedged)) do { if (interruptible) end = wait_event_interruptible_timeout(ring->irq_queue, @@ -1035,7 +1035,7 @@ static int __wait_seqno(struct intel_ring_buffer *ring, u32 seqno, end = wait_event_timeout(ring->irq_queue, EXIT_COND, timeout_jiffies); - ret = i915_gem_check_wedge(dev_priv, interruptible); + ret = i915_gem_check_wedge(&dev_priv->gpu_error, interruptible); if (ret) end = ret; } while (end == 0 && wait_forever); @@ -1081,7 +1081,7 @@ i915_wait_seqno(struct intel_ring_buffer *ring, uint32_t seqno) BUG_ON(!mutex_is_locked(&dev->struct_mutex)); BUG_ON(seqno == 0); - ret = i915_gem_check_wedge(dev_priv, interruptible); + ret = i915_gem_check_wedge(&dev_priv->gpu_error, interruptible); if (ret) return ret; @@ -1146,7 +1146,7 @@ i915_gem_object_wait_rendering__nonblocking(struct drm_i915_gem_object *obj, if (seqno == 0) return 0; - ret = i915_gem_check_wedge(dev_priv, true); + ret = i915_gem_check_wedge(&dev_priv->gpu_error, true); if (ret) return ret; @@ -1379,7 +1379,7 @@ out: /* If this -EIO is due to a gpu hang, give the reset code a * chance to clean up the mess. Otherwise return the proper * SIGBUS. */ - if (!atomic_read(&dev_priv->mm.wedged)) + if (!atomic_read(&dev_priv->gpu_error.wedged)) return VM_FAULT_SIGBUS; case -EAGAIN: /* Give the error handler a chance to run and move the @@ -3390,7 +3390,7 @@ i915_gem_ring_throttle(struct drm_device *dev, struct drm_file *file) u32 seqno = 0; int ret; - if (atomic_read(&dev_priv->mm.wedged)) + if (atomic_read(&dev_priv->gpu_error.wedged)) return -EIO; spin_lock(&file_priv->mm.lock); @@ -3978,9 +3978,9 @@ i915_gem_entervt_ioctl(struct drm_device *dev, void *data, if (drm_core_check_feature(dev, DRIVER_MODESET)) return 0; - if (atomic_read(&dev_priv->mm.wedged)) { + if (atomic_read(&dev_priv->gpu_error.wedged)) { DRM_ERROR("Reenabling wedged hardware, good luck\n"); - atomic_set(&dev_priv->mm.wedged, 0); + atomic_set(&dev_priv->gpu_error.wedged, 0); } mutex_lock(&dev->struct_mutex); diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c index c768ebdf8a27..f2c0016fa533 100644 --- a/drivers/gpu/drm/i915/i915_irq.c +++ b/drivers/gpu/drm/i915/i915_irq.c @@ -871,11 +871,11 @@ static void i915_error_work_func(struct work_struct *work) kobject_uevent_env(&dev->primary->kdev.kobj, KOBJ_CHANGE, error_event); - if (atomic_read(&dev_priv->mm.wedged)) { + if (atomic_read(&dev_priv->gpu_error.wedged)) { DRM_DEBUG_DRIVER("resetting chip\n"); kobject_uevent_env(&dev->primary->kdev.kobj, KOBJ_CHANGE, reset_event); if (!i915_reset(dev)) { - atomic_set(&dev_priv->mm.wedged, 0); + atomic_set(&dev_priv->gpu_error.wedged, 0); kobject_uevent_env(&dev->primary->kdev.kobj, KOBJ_CHANGE, reset_done_event); } complete_all(&dev_priv->gpu_error.completion); @@ -1483,7 +1483,7 @@ void i915_handle_error(struct drm_device *dev, bool wedged) if (wedged) { INIT_COMPLETION(dev_priv->gpu_error.completion); - atomic_set(&dev_priv->mm.wedged, 1); + atomic_set(&dev_priv->gpu_error.wedged, 1); /* * Wakeup waiting processes so they don't hang diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index b35902e5d925..160aa5f76118 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -2223,7 +2223,7 @@ intel_finish_fb(struct drm_framebuffer *old_fb) WARN_ON(waitqueue_active(&dev_priv->pending_flip_queue)); wait_event(dev_priv->pending_flip_queue, - atomic_read(&dev_priv->mm.wedged) || + atomic_read(&dev_priv->gpu_error.wedged) || atomic_read(&obj->pending_flip) == 0); /* Big Hammer, we also need to ensure that any pending @@ -2871,7 +2871,7 @@ static bool intel_crtc_has_pending_flip(struct drm_crtc *crtc) unsigned long flags; bool pending; - if (atomic_read(&dev_priv->mm.wedged)) + if (atomic_read(&dev_priv->gpu_error.wedged)) return false; spin_lock_irqsave(&dev->event_lock, flags); diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.c b/drivers/gpu/drm/i915/intel_ringbuffer.c index d6b06aa4c05c..9438bcd50678 100644 --- a/drivers/gpu/drm/i915/intel_ringbuffer.c +++ b/drivers/gpu/drm/i915/intel_ringbuffer.c @@ -1371,7 +1371,8 @@ static int ring_wait_for_space(struct intel_ring_buffer *ring, int n) msleep(1); - ret = i915_gem_check_wedge(dev_priv, dev_priv->mm.interruptible); + ret = i915_gem_check_wedge(&dev_priv->gpu_error, + dev_priv->mm.interruptible); if (ret) return ret; } while (!time_after(jiffies, end)); @@ -1460,7 +1461,8 @@ int intel_ring_begin(struct intel_ring_buffer *ring, drm_i915_private_t *dev_priv = ring->dev->dev_private; int ret; - ret = i915_gem_check_wedge(dev_priv, dev_priv->mm.interruptible); + ret = i915_gem_check_wedge(&dev_priv->gpu_error, + dev_priv->mm.interruptible); if (ret) return ret; From 308887aad14c4ecc3fc10a3c58ec42641c5e4423 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Wed, 14 Nov 2012 17:14:06 +0100 Subject: [PATCH 031/101] drm/i915: fix reset handling in the throttle ioctl While auditing the code I've noticed one place (the throttle ioctl) which does not yet wait for the reset handler to complete and doesn't properly decode the wedge state into -EAGAIN/-EIO. Fix this up by calling the right helpers. This might explain the oddball "my compositor just died in a successfull gpu reset" reports. Or maybe not, since current mesa doesn't use this ioctl to throttle command submission. The throttle ioctl doesn't take the struct_mutex, so to avoid busy-looping with -EAGAIN while a reset is in process, check for errors first and wait for the handler to complete if a reset is pending by calling i915_gem_wait_for_error. Reviewed-by: Damien Lespiau Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_gem.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index 04b2f92eb456..c96a501b8205 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -3390,8 +3390,13 @@ i915_gem_ring_throttle(struct drm_device *dev, struct drm_file *file) u32 seqno = 0; int ret; - if (atomic_read(&dev_priv->gpu_error.wedged)) - return -EIO; + ret = i915_gem_wait_for_error(&dev_priv->gpu_error); + if (ret) + return ret; + + ret = i915_gem_check_wedge(&dev_priv->gpu_error, false); + if (ret) + return ret; spin_lock(&file_priv->mm.lock); list_for_each_entry(request, &file_priv->mm.request_list, client_list) { From 1f83fee08d625f8d0130f9fe5ef7b17c2e022f3c Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Thu, 15 Nov 2012 17:17:22 +0100 Subject: [PATCH 032/101] drm/i915: clear up wedged transitions We have two important transitions of the wedged state in the current code: - 0 -> 1: This means a hang has been detected, and signals to everyone that they please get of any locks, so that the reset work item can do its job. - 1 -> 0: The reset handler has completed. Now the last transition mixes up two states: "Reset completed and successful" and "Reset failed". To distinguish these two we do some tricks with the reset completion, but I simply could not convince myself that this doesn't race under odd circumstances. Hence split this up, and add a new terminal state indicating that the hw is gone for good. Also add explicit #defines for both states, update comments. v2: Split out the reset handling bugfix for the throttle ioctl. v3: s/tmp/wedged/ sugested by Chris Wilson. Also fixup up a rebase error which prevented this patch from actually compiling. v4: To unify the wedged state with the reset counter, keep the reset-in-progress state just as a flag. The terminally-wedged state is now denoted with a big number. v5: Add a comment to the reset_counter special values explaining that WEDGED & RESET_IN_PROGRESS needs to be true for the code to be correct. v6: Fixup logic errors introduced with the wedged+reset_counter unification. Since WEDGED implies reset-in-progress (in a way we're terminally stuck in the dead-but-reset-not-completed state), we need ensure that we check for this everywhere. The specific bug was in wait_for_error, which would simply have timed out. v7: Extract an inline i915_reset_in_progress helper to make the code more readable. Also annote the reset-in-progress case with an unlikely, to help the compiler optimize the fastpath. Do the same for the terminally wedged case with i915_terminally_wedged. Reviewed-by: Damien Lespiau Signed-Off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_debugfs.c | 2 +- drivers/gpu/drm/i915/i915_drv.h | 40 +++++++++++++++++++++-- drivers/gpu/drm/i915/i915_gem.c | 49 ++++++++++------------------ drivers/gpu/drm/i915/i915_irq.c | 23 ++++++++----- drivers/gpu/drm/i915/intel_display.c | 4 +-- 5 files changed, 74 insertions(+), 44 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_debugfs.c b/drivers/gpu/drm/i915/i915_debugfs.c index e1b7eaf60d24..384f19368a1d 100644 --- a/drivers/gpu/drm/i915/i915_debugfs.c +++ b/drivers/gpu/drm/i915/i915_debugfs.c @@ -1672,7 +1672,7 @@ i915_wedged_read(struct file *filp, len = snprintf(buf, sizeof(buf), "wedged : %d\n", - atomic_read(&dev_priv->gpu_error.wedged)); + atomic_read(&dev_priv->gpu_error.reset_counter)); if (len > sizeof(buf)) len = sizeof(buf); diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 62da6c7a4884..c84743bb6937 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -771,11 +771,37 @@ struct i915_gpu_error { /* Protected by the above dev->gpu_error.lock. */ struct drm_i915_error_state *first_error; struct work_struct work; - struct completion completion; unsigned long last_reset; - atomic_t wedged; + /** + * State variable controlling the reset flow + * + * Upper bits are for the reset counter. + * + * Lowest bit controls the reset state machine: Set means a reset is in + * progress. This state will (presuming we don't have any bugs) decay + * into either unset (successful reset) or the special WEDGED value (hw + * terminally sour). All waiters on the reset_queue will be woken when + * that happens. + */ + atomic_t reset_counter; + + /** + * Special values/flags for reset_counter + * + * Note that the code relies on + * I915_WEDGED & I915_RESET_IN_PROGRESS_FLAG + * being true. + */ +#define I915_RESET_IN_PROGRESS_FLAG 1 +#define I915_WEDGED 0xffffffff + + /** + * Waitqueue to signal when the reset has completed. Used by clients + * that wait for dev_priv->mm.wedged to settle. + */ + wait_queue_head_t reset_queue; /* For gpu hang simulation. */ unsigned int stop_rings; @@ -1543,6 +1569,16 @@ void i915_gem_retire_requests(struct drm_device *dev); void i915_gem_retire_requests_ring(struct intel_ring_buffer *ring); int __must_check i915_gem_check_wedge(struct i915_gpu_error *error, bool interruptible); +static inline bool i915_reset_in_progress(struct i915_gpu_error *error) +{ + return unlikely(atomic_read(&error->reset_counter) + & I915_RESET_IN_PROGRESS_FLAG); +} + +static inline bool i915_terminally_wedged(struct i915_gpu_error *error) +{ + return atomic_read(&error->reset_counter) == I915_WEDGED; +} void i915_gem_reset(struct drm_device *dev); void i915_gem_clflush_object(struct drm_i915_gem_object *obj); diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index c96a501b8205..2ca901194824 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -89,36 +89,32 @@ static void i915_gem_info_remove_obj(struct drm_i915_private *dev_priv, static int i915_gem_wait_for_error(struct i915_gpu_error *error) { - struct completion *x = &error->completion; - unsigned long flags; int ret; - if (!atomic_read(&error->wedged)) +#define EXIT_COND (!i915_reset_in_progress(error)) + if (EXIT_COND) return 0; + /* GPU is already declared terminally dead, give up. */ + if (i915_terminally_wedged(error)) + return -EIO; + /* * Only wait 10 seconds for the gpu reset to complete to avoid hanging * userspace. If it takes that long something really bad is going on and * we should simply try to bail out and fail as gracefully as possible. */ - ret = wait_for_completion_interruptible_timeout(x, 10*HZ); + ret = wait_event_interruptible_timeout(error->reset_queue, + EXIT_COND, + 10*HZ); if (ret == 0) { DRM_ERROR("Timed out waiting for the gpu reset to complete\n"); return -EIO; } else if (ret < 0) { return ret; } +#undef EXIT_COND - if (atomic_read(&error->wedged)) { - /* GPU is hung, bump the completion count to account for - * the token we just consumed so that we never hit zero and - * end up waiting upon a subsequent completion event that - * will never happen. - */ - spin_lock_irqsave(&x->wait.lock, flags); - x->done++; - spin_unlock_irqrestore(&x->wait.lock, flags); - } return 0; } @@ -942,23 +938,14 @@ int i915_gem_check_wedge(struct i915_gpu_error *error, bool interruptible) { - if (atomic_read(&error->wedged)) { - struct completion *x = &error->completion; - bool recovery_complete; - unsigned long flags; - - /* Give the error handler a chance to run. */ - spin_lock_irqsave(&x->wait.lock, flags); - recovery_complete = x->done > 0; - spin_unlock_irqrestore(&x->wait.lock, flags); - + if (i915_reset_in_progress(error)) { /* Non-interruptible callers can't handle -EAGAIN, hence return * -EIO unconditionally for these. */ if (!interruptible) return -EIO; - /* Recovery complete, but still wedged means reset failure. */ - if (recovery_complete) + /* Recovery complete, but the reset failed ... */ + if (i915_terminally_wedged(error)) return -EIO; return -EAGAIN; @@ -1025,7 +1012,7 @@ static int __wait_seqno(struct intel_ring_buffer *ring, u32 seqno, #define EXIT_COND \ (i915_seqno_passed(ring->get_seqno(ring, false), seqno) || \ - atomic_read(&dev_priv->gpu_error.wedged)) + i915_reset_in_progress(&dev_priv->gpu_error)) do { if (interruptible) end = wait_event_interruptible_timeout(ring->irq_queue, @@ -1379,7 +1366,7 @@ out: /* If this -EIO is due to a gpu hang, give the reset code a * chance to clean up the mess. Otherwise return the proper * SIGBUS. */ - if (!atomic_read(&dev_priv->gpu_error.wedged)) + if (i915_terminally_wedged(&dev_priv->gpu_error)) return VM_FAULT_SIGBUS; case -EAGAIN: /* Give the error handler a chance to run and move the @@ -3983,9 +3970,9 @@ i915_gem_entervt_ioctl(struct drm_device *dev, void *data, if (drm_core_check_feature(dev, DRIVER_MODESET)) return 0; - if (atomic_read(&dev_priv->gpu_error.wedged)) { + if (i915_reset_in_progress(&dev_priv->gpu_error)) { DRM_ERROR("Reenabling wedged hardware, good luck\n"); - atomic_set(&dev_priv->gpu_error.wedged, 0); + atomic_set(&dev_priv->gpu_error.reset_counter, 0); } mutex_lock(&dev->struct_mutex); @@ -4069,7 +4056,7 @@ i915_gem_load(struct drm_device *dev) INIT_LIST_HEAD(&dev_priv->fence_regs[i].lru_list); INIT_DELAYED_WORK(&dev_priv->mm.retire_work, i915_gem_retire_work_handler); - init_completion(&dev_priv->gpu_error.completion); + init_waitqueue_head(&dev_priv->gpu_error.reset_queue); /* On GEN3 we really need to make sure the ARB C3 LP bit is set */ if (IS_GEN3(dev)) { diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c index f2c0016fa533..4562c5406ef8 100644 --- a/drivers/gpu/drm/i915/i915_irq.c +++ b/drivers/gpu/drm/i915/i915_irq.c @@ -862,8 +862,10 @@ done: */ static void i915_error_work_func(struct work_struct *work) { - drm_i915_private_t *dev_priv = container_of(work, drm_i915_private_t, - gpu_error.work); + struct i915_gpu_error *error = container_of(work, struct i915_gpu_error, + work); + drm_i915_private_t *dev_priv = container_of(error, drm_i915_private_t, + gpu_error); struct drm_device *dev = dev_priv->dev; char *error_event[] = { "ERROR=1", NULL }; char *reset_event[] = { "RESET=1", NULL }; @@ -871,14 +873,18 @@ static void i915_error_work_func(struct work_struct *work) kobject_uevent_env(&dev->primary->kdev.kobj, KOBJ_CHANGE, error_event); - if (atomic_read(&dev_priv->gpu_error.wedged)) { + if (i915_reset_in_progress(error)) { DRM_DEBUG_DRIVER("resetting chip\n"); kobject_uevent_env(&dev->primary->kdev.kobj, KOBJ_CHANGE, reset_event); + if (!i915_reset(dev)) { - atomic_set(&dev_priv->gpu_error.wedged, 0); + atomic_set(&error->reset_counter, 0); kobject_uevent_env(&dev->primary->kdev.kobj, KOBJ_CHANGE, reset_done_event); + } else { + atomic_set(&error->reset_counter, I915_WEDGED); } - complete_all(&dev_priv->gpu_error.completion); + + wake_up_all(&dev_priv->gpu_error.reset_queue); } } @@ -1482,11 +1488,12 @@ void i915_handle_error(struct drm_device *dev, bool wedged) i915_report_and_clear_eir(dev); if (wedged) { - INIT_COMPLETION(dev_priv->gpu_error.completion); - atomic_set(&dev_priv->gpu_error.wedged, 1); + atomic_set(&dev_priv->gpu_error.reset_counter, + I915_RESET_IN_PROGRESS_FLAG); /* - * Wakeup waiting processes so they don't hang + * Wakeup waiting processes so that the reset work item + * doesn't deadlock trying to grab various locks. */ for_each_ring(ring, dev_priv, i) wake_up_all(&ring->irq_queue); diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 160aa5f76118..77254460a5cb 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -2223,7 +2223,7 @@ intel_finish_fb(struct drm_framebuffer *old_fb) WARN_ON(waitqueue_active(&dev_priv->pending_flip_queue)); wait_event(dev_priv->pending_flip_queue, - atomic_read(&dev_priv->gpu_error.wedged) || + i915_reset_in_progress(&dev_priv->gpu_error) || atomic_read(&obj->pending_flip) == 0); /* Big Hammer, we also need to ensure that any pending @@ -2871,7 +2871,7 @@ static bool intel_crtc_has_pending_flip(struct drm_crtc *crtc) unsigned long flags; bool pending; - if (atomic_read(&dev_priv->gpu_error.wedged)) + if (i915_reset_in_progress(&dev_priv->gpu_error)) return false; spin_lock_irqsave(&dev->event_lock, flags); From d0a57789d5ec807fc218151b2fb2de4da30fbef5 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Tue, 9 Oct 2012 19:24:37 +0100 Subject: [PATCH 033/101] drm/i915: Only insert the mb() before updating the fence parameter With a fence, we only need to insert a memory barrier around the actual fence alteration for CPU accesses through the GTT. Performing the barrier in flush-fence was inserting unnecessary and expensive barriers for never fenced objects. Note removing the barriers from flush-fence, which was effectively a barrier before every direct access through the GTT, revealed that we where missing a barrier before the first access through the GTT. Lack of that barrier was sufficient to cause GPU hangs. v2: Add a couple more comments to explain the new barriers Signed-off-by: Chris Wilson Reviewed-by: Daniel Vetter Reviewed-by: Jesse Barnes Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_gem.c | 40 ++++++++++++++++++++++++--------- 1 file changed, 30 insertions(+), 10 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index 2ca901194824..ce706555d011 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -2611,9 +2611,22 @@ static void i830_write_fence_reg(struct drm_device *dev, int reg, POSTING_READ(FENCE_REG_830_0 + reg * 4); } +inline static bool i915_gem_object_needs_mb(struct drm_i915_gem_object *obj) +{ + return obj && obj->base.read_domains & I915_GEM_DOMAIN_GTT; +} + static void i915_gem_write_fence(struct drm_device *dev, int reg, struct drm_i915_gem_object *obj) { + struct drm_i915_private *dev_priv = dev->dev_private; + + /* Ensure that all CPU reads are completed before installing a fence + * and all writes before removing the fence. + */ + if (i915_gem_object_needs_mb(dev_priv->fence_regs[reg].obj)) + mb(); + switch (INTEL_INFO(dev)->gen) { case 7: case 6: @@ -2623,6 +2636,12 @@ static void i915_gem_write_fence(struct drm_device *dev, int reg, case 2: i830_write_fence_reg(dev, reg, obj); break; default: BUG(); } + + /* And similarly be paranoid that no direct access to this region + * is reordered to before the fence is installed. + */ + if (i915_gem_object_needs_mb(obj)) + mb(); } static inline int fence_number(struct drm_i915_private *dev_priv, @@ -2652,7 +2671,7 @@ static void i915_gem_object_update_fence(struct drm_i915_gem_object *obj, } static int -i915_gem_object_flush_fence(struct drm_i915_gem_object *obj) +i915_gem_object_wait_fence(struct drm_i915_gem_object *obj) { if (obj->last_fenced_seqno) { int ret = i915_wait_seqno(obj->ring, obj->last_fenced_seqno); @@ -2662,12 +2681,6 @@ i915_gem_object_flush_fence(struct drm_i915_gem_object *obj) obj->last_fenced_seqno = 0; } - /* Ensure that all CPU reads are completed before installing a fence - * and all writes before removing the fence. - */ - if (obj->base.read_domains & I915_GEM_DOMAIN_GTT) - mb(); - obj->fenced_gpu_access = false; return 0; } @@ -2678,7 +2691,7 @@ i915_gem_object_put_fence(struct drm_i915_gem_object *obj) struct drm_i915_private *dev_priv = obj->base.dev->dev_private; int ret; - ret = i915_gem_object_flush_fence(obj); + ret = i915_gem_object_wait_fence(obj); if (ret) return ret; @@ -2752,7 +2765,7 @@ i915_gem_object_get_fence(struct drm_i915_gem_object *obj) * will need to serialise the write to the associated fence register? */ if (obj->fence_dirty) { - ret = i915_gem_object_flush_fence(obj); + ret = i915_gem_object_wait_fence(obj); if (ret) return ret; } @@ -2773,7 +2786,7 @@ i915_gem_object_get_fence(struct drm_i915_gem_object *obj) if (reg->obj) { struct drm_i915_gem_object *old = reg->obj; - ret = i915_gem_object_flush_fence(old); + ret = i915_gem_object_wait_fence(old); if (ret) return ret; @@ -3068,6 +3081,13 @@ i915_gem_object_set_to_gtt_domain(struct drm_i915_gem_object *obj, bool write) i915_gem_object_flush_cpu_write_domain(obj); + /* Serialise direct access to this object with the barriers for + * coherent writes from the GPU, by effectively invalidating the + * GTT domain upon first access. + */ + if ((obj->base.read_domains & I915_GEM_DOMAIN_GTT) == 0) + mb(); + old_write_domain = obj->base.write_domain; old_read_domains = obj->base.read_domains; From 97c809fd9cf5e914322b53773ad0d67efe503fde Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Tue, 9 Oct 2012 19:24:38 +0100 Subject: [PATCH 034/101] drm/i915: Only apply the mb() when flushing the GTT domain during a finish Now that we seem to have brought order to the GTT barriers, the last one to review is the terminal barrier before we unbind the buffer from the GTT. This needs to only be performed if the buffer still resides in the GTT domain, and so we can skip some needless barriers otherwise. Signed-off-by: Chris Wilson Reviewed-by: Jesse Barnes Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_gem.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index ce706555d011..5bb370fdc99c 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -2407,15 +2407,15 @@ static void i915_gem_object_finish_gtt(struct drm_i915_gem_object *obj) { u32 old_write_domain, old_read_domains; - /* Act a barrier for all accesses through the GTT */ - mb(); - /* Force a pagefault for domain tracking on next user access */ i915_gem_release_mmap(obj); if ((obj->base.read_domains & I915_GEM_DOMAIN_GTT) == 0) return; + /* Wait for any direct GTT access to complete */ + mb(); + old_read_domains = obj->base.read_domains; old_write_domain = obj->base.write_domain; From f69061bedd6ea63f271fe97914364def2f33fc6b Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Thu, 6 Dec 2012 09:01:42 +0100 Subject: [PATCH 035/101] drm/i915: create a race-free reset detection With the previous patch the state transition handling of the reset code itself is now (hopefully) race free and solid. But that still leaves out everyone else - with the various lock-free wait paths we have there's the possibility that the reset happens between the point where we read the seqno we should wait on and the actual wait. And if __wait_seqno then never sees the RESET_IN_PROGRESS state, we'll happily wait for a seqno which will in all likelyhood never signal. In practice this is not a big problem since the X server gets constantly interrupted, and can then submit more work (hopefully) to unblock everyone else: As soon as a new seqno write lands, all waiters will unblock. But running the i-g-t reset testcase ZZ_hangman can expose this race, especially on slower hw with fewer cpu cores. Now looking forward to ARB_robustness and friends that's not the best possible behaviour, hence this patch adds a reset_counter to be able to detect any reset, even if a given thread never observed the in-progress state. The important part is to correctly order things: - The write side needs to increment the counter after any seqno gets reset. Hence we need to do that at the end of the reset work, and again wake everyone up. We also need to place a barrier in between any possible seqno changes and the counter increment, since any unlock operations only guarantee that nothing leaks out, but not that at later load operation gets moved ahead. - On the read side we need to ensure that no reset can sneak in and invalidate the seqno. In all cases we can use the one-sided barrier that unlock operations guarantee (of the lock protecting the respective seqno/ring pair) to ensure correct ordering. Hence it is sufficient to place the atomic read before the mutex/spin_unlock and no additional barriers are required. The end-result of all this is that we need to wake up everyone twice in a reset operation: - First, before the reset starts, to get any lockholders of the locks, so that the reset can proceed. - Second, after the reset is completed, to allow waiters to properly and reliably detect the reset condition and bail out. I admit that this entire reset_counter thing smells a bit like overkill, but I think it's justified since it makes it really explicit what the bail-out condition is. And we need a reset counter anyway to implement ARB_robustness, and imo with finer-grained locking on the horizont this is the most resilient scheme I could think of. v2: Drop spurious change in the wait_for_error EXIT_COND - we only need to wait until we leave the reset-in-progress wedged state. v3: Don't play tricks with barriers in the throttle ioctl, the spin_unlock is barrier enough. I've also considered using a little helper to grab the current reset_counter, but then decided that hiding the atomic_read isn't a great idea, since having it explicitly show up in the code is a nice remainder to reviews to check the memory barriers. v4: Add a comment to explain why we need to fall through in __wait_seqno in the end variable assignments. v5: Review from Damien: - s/smb/smp/ in a comment - don't increment the reset counter after we've set it to WEDGED. Now we (again) properly wedge the gpu when the reset fails. Reviewed-by: Damien Lespiau Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_drv.h | 11 ++++++++-- drivers/gpu/drm/i915/i915_gem.c | 36 ++++++++++++++++++++++++++++----- drivers/gpu/drm/i915/i915_irq.c | 30 ++++++++++++++++++++++----- 3 files changed, 65 insertions(+), 12 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index c84743bb6937..56ece50910a8 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -775,9 +775,16 @@ struct i915_gpu_error { unsigned long last_reset; /** - * State variable controlling the reset flow + * State variable and reset counter controlling the reset flow * - * Upper bits are for the reset counter. + * Upper bits are for the reset counter. This counter is used by the + * wait_seqno code to race-free noticed that a reset event happened and + * that it needs to restart the entire ioctl (since most likely the + * seqno it waited for won't ever signal anytime soon). + * + * This is important for lock-free wait paths, where no contended lock + * naturally enforces the correct ordering between the bail-out of the + * waiter and the gpu reset work code. * * Lowest bit controls the reset state machine: Set means a reset is in * progress. This state will (presuming we don't have any bugs) decay diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index 5bb370fdc99c..5226ebcac33a 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -976,13 +976,22 @@ i915_gem_check_olr(struct intel_ring_buffer *ring, u32 seqno) * __wait_seqno - wait until execution of seqno has finished * @ring: the ring expected to report seqno * @seqno: duh! + * @reset_counter: reset sequence associated with the given seqno * @interruptible: do an interruptible wait (normally yes) * @timeout: in - how long to wait (NULL forever); out - how much time remaining * + * Note: It is of utmost importance that the passed in seqno and reset_counter + * values have been read by the caller in an smp safe manner. Where read-side + * locks are involved, it is sufficient to read the reset_counter before + * unlocking the lock that protects the seqno. For lockless tricks, the + * reset_counter _must_ be read before, and an appropriate smp_rmb must be + * inserted. + * * Returns 0 if the seqno was found within the alloted time. Else returns the * errno with remaining time filled in timeout argument. */ static int __wait_seqno(struct intel_ring_buffer *ring, u32 seqno, + unsigned reset_counter, bool interruptible, struct timespec *timeout) { drm_i915_private_t *dev_priv = ring->dev->dev_private; @@ -1012,7 +1021,8 @@ static int __wait_seqno(struct intel_ring_buffer *ring, u32 seqno, #define EXIT_COND \ (i915_seqno_passed(ring->get_seqno(ring, false), seqno) || \ - i915_reset_in_progress(&dev_priv->gpu_error)) + i915_reset_in_progress(&dev_priv->gpu_error) || \ + reset_counter != atomic_read(&dev_priv->gpu_error.reset_counter)) do { if (interruptible) end = wait_event_interruptible_timeout(ring->irq_queue, @@ -1022,6 +1032,13 @@ static int __wait_seqno(struct intel_ring_buffer *ring, u32 seqno, end = wait_event_timeout(ring->irq_queue, EXIT_COND, timeout_jiffies); + /* We need to check whether any gpu reset happened in between + * the caller grabbing the seqno and now ... */ + if (reset_counter != atomic_read(&dev_priv->gpu_error.reset_counter)) + end = -EAGAIN; + + /* ... but upgrade the -EGAIN to an -EIO if the gpu is truely + * gone. */ ret = i915_gem_check_wedge(&dev_priv->gpu_error, interruptible); if (ret) end = ret; @@ -1076,7 +1093,9 @@ i915_wait_seqno(struct intel_ring_buffer *ring, uint32_t seqno) if (ret) return ret; - return __wait_seqno(ring, seqno, interruptible, NULL); + return __wait_seqno(ring, seqno, + atomic_read(&dev_priv->gpu_error.reset_counter), + interruptible, NULL); } /** @@ -1123,6 +1142,7 @@ i915_gem_object_wait_rendering__nonblocking(struct drm_i915_gem_object *obj, struct drm_device *dev = obj->base.dev; struct drm_i915_private *dev_priv = dev->dev_private; struct intel_ring_buffer *ring = obj->ring; + unsigned reset_counter; u32 seqno; int ret; @@ -1141,8 +1161,9 @@ i915_gem_object_wait_rendering__nonblocking(struct drm_i915_gem_object *obj, if (ret) return ret; + reset_counter = atomic_read(&dev_priv->gpu_error.reset_counter); mutex_unlock(&dev->struct_mutex); - ret = __wait_seqno(ring, seqno, true, NULL); + ret = __wait_seqno(ring, seqno, reset_counter, true, NULL); mutex_lock(&dev->struct_mutex); i915_gem_retire_requests_ring(ring); @@ -2297,10 +2318,12 @@ i915_gem_object_flush_active(struct drm_i915_gem_object *obj) int i915_gem_wait_ioctl(struct drm_device *dev, void *data, struct drm_file *file) { + drm_i915_private_t *dev_priv = dev->dev_private; struct drm_i915_gem_wait *args = data; struct drm_i915_gem_object *obj; struct intel_ring_buffer *ring = NULL; struct timespec timeout_stack, *timeout = NULL; + unsigned reset_counter; u32 seqno = 0; int ret = 0; @@ -2341,9 +2364,10 @@ i915_gem_wait_ioctl(struct drm_device *dev, void *data, struct drm_file *file) } drm_gem_object_unreference(&obj->base); + reset_counter = atomic_read(&dev_priv->gpu_error.reset_counter); mutex_unlock(&dev->struct_mutex); - ret = __wait_seqno(ring, seqno, true, timeout); + ret = __wait_seqno(ring, seqno, reset_counter, true, timeout); if (timeout) { WARN_ON(!timespec_valid(timeout)); args->timeout_ns = timespec_to_ns(timeout); @@ -3394,6 +3418,7 @@ i915_gem_ring_throttle(struct drm_device *dev, struct drm_file *file) unsigned long recent_enough = jiffies - msecs_to_jiffies(20); struct drm_i915_gem_request *request; struct intel_ring_buffer *ring = NULL; + unsigned reset_counter; u32 seqno = 0; int ret; @@ -3413,12 +3438,13 @@ i915_gem_ring_throttle(struct drm_device *dev, struct drm_file *file) ring = request->ring; seqno = request->seqno; } + reset_counter = atomic_read(&dev_priv->gpu_error.reset_counter); spin_unlock(&file_priv->mm.lock); if (seqno == 0) return 0; - ret = __wait_seqno(ring, seqno, true, NULL); + ret = __wait_seqno(ring, seqno, reset_counter, true, NULL); if (ret == 0) queue_delayed_work(dev_priv->wq, &dev_priv->mm.retire_work, 0); diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c index 4562c5406ef8..f833f2c155f8 100644 --- a/drivers/gpu/drm/i915/i915_irq.c +++ b/drivers/gpu/drm/i915/i915_irq.c @@ -867,9 +867,11 @@ static void i915_error_work_func(struct work_struct *work) drm_i915_private_t *dev_priv = container_of(error, drm_i915_private_t, gpu_error); struct drm_device *dev = dev_priv->dev; + struct intel_ring_buffer *ring; char *error_event[] = { "ERROR=1", NULL }; char *reset_event[] = { "RESET=1", NULL }; char *reset_done_event[] = { "ERROR=0", NULL }; + int i, ret; kobject_uevent_env(&dev->primary->kdev.kobj, KOBJ_CHANGE, error_event); @@ -877,13 +879,31 @@ static void i915_error_work_func(struct work_struct *work) DRM_DEBUG_DRIVER("resetting chip\n"); kobject_uevent_env(&dev->primary->kdev.kobj, KOBJ_CHANGE, reset_event); - if (!i915_reset(dev)) { - atomic_set(&error->reset_counter, 0); - kobject_uevent_env(&dev->primary->kdev.kobj, KOBJ_CHANGE, reset_done_event); + ret = i915_reset(dev); + + if (ret == 0) { + /* + * After all the gem state is reset, increment the reset + * counter and wake up everyone waiting for the reset to + * complete. + * + * Since unlock operations are a one-sided barrier only, + * we need to insert a barrier here to order any seqno + * updates before + * the counter increment. + */ + smp_mb__before_atomic_inc(); + atomic_inc(&dev_priv->gpu_error.reset_counter); + + kobject_uevent_env(&dev->primary->kdev.kobj, + KOBJ_CHANGE, reset_done_event); } else { atomic_set(&error->reset_counter, I915_WEDGED); } + for_each_ring(ring, dev_priv, i) + wake_up_all(&ring->irq_queue); + wake_up_all(&dev_priv->gpu_error.reset_queue); } } @@ -1488,8 +1508,8 @@ void i915_handle_error(struct drm_device *dev, bool wedged) i915_report_and_clear_eir(dev); if (wedged) { - atomic_set(&dev_priv->gpu_error.reset_counter, - I915_RESET_IN_PROGRESS_FLAG); + atomic_set_mask(I915_RESET_IN_PROGRESS_FLAG, + &dev_priv->gpu_error.reset_counter); /* * Wakeup waiting processes so that the reset work item From 7db0ba242b3a7ddcfc1450bc50eb3102c68f0244 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Thu, 6 Dec 2012 16:23:37 +0100 Subject: [PATCH 036/101] drm/i915: clarify concurrent hang detect/gpu reset consistency Damien Lespiau wondered how race the gpu reset/hang detection code is against concurrent gpu resets/hang detections or combinations thereof. Luckily the single work item is guranteed to never run concurrently, so reset handling is already single-threaded. Hence we only have to worry about concurrent hang detections, or a hang detection firing off while we're still processing an older gpu reset request. Due to the new mechanism of setting the reset in progress flag and the ordering guaranteed by the schedule_work function there's nothing to do but add a comment explaining why we're safe. The only thing I've noticed is that we still try to reset the gpu now, even when it is declared terminally wedged. Add a check for that to avoid continous warnings about failed resets, in case the hangcheck timer ever gets stuck. Reviewed-by: Damien Lespiau Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_irq.c | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c index f833f2c155f8..943db1001cfd 100644 --- a/drivers/gpu/drm/i915/i915_irq.c +++ b/drivers/gpu/drm/i915/i915_irq.c @@ -875,9 +875,20 @@ static void i915_error_work_func(struct work_struct *work) kobject_uevent_env(&dev->primary->kdev.kobj, KOBJ_CHANGE, error_event); - if (i915_reset_in_progress(error)) { + /* + * Note that there's only one work item which does gpu resets, so we + * need not worry about concurrent gpu resets potentially incrementing + * error->reset_counter twice. We only need to take care of another + * racing irq/hangcheck declaring the gpu dead for a second time. A + * quick check for that is good enough: schedule_work ensures the + * correct ordering between hang detection and this work item, and since + * the reset in-progress bit is only ever set by code outside of this + * work we don't need to worry about any other races. + */ + if (i915_reset_in_progress(error) && !i915_terminally_wedged(error)) { DRM_DEBUG_DRIVER("resetting chip\n"); - kobject_uevent_env(&dev->primary->kdev.kobj, KOBJ_CHANGE, reset_event); + kobject_uevent_env(&dev->primary->kdev.kobj, KOBJ_CHANGE, + reset_event); ret = i915_reset(dev); From 1ffff60320879830e469e26062c18f75236822ba Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Tue, 22 Jan 2013 12:50:34 +0200 Subject: [PATCH 037/101] drm/i915: add quirk to invert brightness on eMachines G725 Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=59628 Reported-by: Roland Gruber Signed-off-by: Jani Nikula Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_display.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 77254460a5cb..44f9d8f73a20 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -8599,6 +8599,9 @@ static struct intel_quirk intel_quirks[] = { /* Acer Aspire 5734Z must invert backlight brightness */ { 0x2a42, 0x1025, 0x0459, quirk_invert_brightness }, + + /* Acer/eMachines G725 */ + { 0x2a42, 0x1025, 0x0210, quirk_invert_brightness }, }; static void intel_init_quirks(struct drm_device *dev) From 01e3a8feb40e54b962a20fa7eb595c5efef5e109 Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Tue, 22 Jan 2013 12:50:35 +0200 Subject: [PATCH 038/101] drm/i915: add quirk to invert brightness on eMachines e725 Bugzilla: https://bugzilla.kernel.org/show_bug.cgi?id=31522#c35 [Note: There are more than one broken setups in the bug. This fixes one.] Reported-by: Martins Signed-off-by: Jani Nikula Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_display.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 44f9d8f73a20..8575a62d29d3 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -8602,6 +8602,9 @@ static struct intel_quirk intel_quirks[] = { /* Acer/eMachines G725 */ { 0x2a42, 0x1025, 0x0210, quirk_invert_brightness }, + + /* Acer/eMachines e725 */ + { 0x2a42, 0x1025, 0x0212, quirk_invert_brightness }, }; static void intel_init_quirks(struct drm_device *dev) From 5559ecadad5a73b27f863e92f4b4f369501dce6f Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Tue, 22 Jan 2013 12:50:36 +0200 Subject: [PATCH 039/101] drm/i915: add quirk to invert brightness on Packard Bell NCL20 Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=44156 Reported-by: Alan Zimmerman Signed-off-by: Jani Nikula Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_display.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 8575a62d29d3..726278668ab6 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -8605,6 +8605,9 @@ static struct intel_quirk intel_quirks[] = { /* Acer/eMachines e725 */ { 0x2a42, 0x1025, 0x0212, quirk_invert_brightness }, + + /* Acer/Packard Bell NCL20 */ + { 0x2a42, 0x1025, 0x034b, quirk_invert_brightness }, }; static void intel_init_quirks(struct drm_device *dev) From 99433931950f33039d9e1a52b4ed9af3f1b58e84 Mon Sep 17 00:00:00 2001 From: Mika Kuoppala Date: Tue, 22 Jan 2013 14:12:17 +0200 Subject: [PATCH 040/101] drm/i915: use gem_set_seqno() on hardware init When machine was rebooted or module was reloaded, gem_hw_init() set last_seqno to be identical to next_seqno. This lead to situation that waits for first ever request always passed immediately regardless if it was actually executed. Use gem_set_seqno() to be consistent how hw is initialized on init, wrap and on resume. Signed-off-by: Mika Kuoppala Reviewed-by: Chris Wilson Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_gem.c | 6 ++++-- drivers/gpu/drm/i915/intel_ringbuffer.c | 2 -- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index 5226ebcac33a..801f77ece72e 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -3941,8 +3941,6 @@ i915_gem_init_hw(struct drm_device *dev) i915_gem_init_swizzling(dev); - dev_priv->next_seqno = dev_priv->last_seqno = (u32)~0 - 0x1000; - ret = intel_init_render_ring_buffer(dev); if (ret) return ret; @@ -3959,6 +3957,10 @@ i915_gem_init_hw(struct drm_device *dev) goto cleanup_bsd_ring; } + ret = i915_gem_set_seqno(dev, ((u32)~0 - 0x1000)); + if (ret) + return ret; + /* * XXX: There was some w/a described somewhere suggesting loading * contexts before PPGTT. diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.c b/drivers/gpu/drm/i915/intel_ringbuffer.c index 9438bcd50678..dc6ae2fa1cee 100644 --- a/drivers/gpu/drm/i915/intel_ringbuffer.c +++ b/drivers/gpu/drm/i915/intel_ringbuffer.c @@ -1223,8 +1223,6 @@ static int intel_init_ring_buffer(struct drm_device *dev, if (IS_I830(ring->dev) || IS_845G(ring->dev)) ring->effective_size -= 128; - intel_ring_init_seqno(ring, dev_priv->last_seqno); - return 0; err_unmap: From 7b9f35a6dd72f89452c58bbdbaf063027bf857ec Mon Sep 17 00:00:00 2001 From: Wang Xingchao Date: Tue, 22 Jan 2013 23:25:25 +0800 Subject: [PATCH 041/101] drm/i915: HDMI/DP - ELD info refresh support for Haswell MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ELD info should be updated dynamically according to hot plug event. For haswell chip, clear/set the eld valid bit and output enable bit from callback intel_disable/eanble_ddi(). Reviewed-by: Ville Syrjälä Reviewed-by: Rodrigo Vivi Signed-off-by: Wang Xingchao Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_ddi.c | 21 +++++++++++++++++++++ drivers/gpu/drm/i915/intel_display.c | 4 ++++ drivers/gpu/drm/i915/intel_drv.h | 1 + 3 files changed, 26 insertions(+) diff --git a/drivers/gpu/drm/i915/intel_ddi.c b/drivers/gpu/drm/i915/intel_ddi.c index 2e904a5cd6cb..33b911218023 100644 --- a/drivers/gpu/drm/i915/intel_ddi.c +++ b/drivers/gpu/drm/i915/intel_ddi.c @@ -677,6 +677,7 @@ static void intel_ddi_mode_set(struct drm_encoder *encoder, DRM_DEBUG_KMS("Preparing DDI mode for Haswell on port %c, pipe %c\n", port_name(port), pipe_name(pipe)); + intel_crtc->eld_vld = false; if (type == INTEL_OUTPUT_DISPLAYPORT || type == INTEL_OUTPUT_EDP) { struct intel_dp *intel_dp = enc_to_intel_dp(encoder); @@ -1287,10 +1288,14 @@ static void intel_ddi_post_disable(struct intel_encoder *intel_encoder) static void intel_enable_ddi(struct intel_encoder *intel_encoder) { struct drm_encoder *encoder = &intel_encoder->base; + struct drm_crtc *crtc = encoder->crtc; + struct intel_crtc *intel_crtc = to_intel_crtc(crtc); + int pipe = intel_crtc->pipe; struct drm_device *dev = encoder->dev; struct drm_i915_private *dev_priv = dev->dev_private; enum port port = intel_ddi_get_encoder_port(intel_encoder); int type = intel_encoder->type; + uint32_t tmp; if (type == INTEL_OUTPUT_HDMI) { /* In HDMI/DVI mode, the port width, and swing/emphasis values @@ -1303,18 +1308,34 @@ static void intel_enable_ddi(struct intel_encoder *intel_encoder) ironlake_edp_backlight_on(intel_dp); } + + if (intel_crtc->eld_vld) { + tmp = I915_READ(HSW_AUD_PIN_ELD_CP_VLD); + tmp |= ((AUDIO_OUTPUT_ENABLE_A | AUDIO_ELD_VALID_A) << (pipe * 4)); + I915_WRITE(HSW_AUD_PIN_ELD_CP_VLD, tmp); + } } static void intel_disable_ddi(struct intel_encoder *intel_encoder) { struct drm_encoder *encoder = &intel_encoder->base; + struct drm_crtc *crtc = encoder->crtc; + struct intel_crtc *intel_crtc = to_intel_crtc(crtc); + int pipe = intel_crtc->pipe; int type = intel_encoder->type; + struct drm_device *dev = encoder->dev; + struct drm_i915_private *dev_priv = dev->dev_private; + uint32_t tmp; if (type == INTEL_OUTPUT_EDP) { struct intel_dp *intel_dp = enc_to_intel_dp(encoder); ironlake_edp_backlight_off(intel_dp); } + + tmp = I915_READ(HSW_AUD_PIN_ELD_CP_VLD); + tmp &= ~((AUDIO_OUTPUT_ENABLE_A | AUDIO_ELD_VALID_A) << (pipe * 4)); + I915_WRITE(HSW_AUD_PIN_ELD_CP_VLD, tmp); } int intel_ddi_get_cdclk_freq(struct drm_i915_private *dev_priv) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 726278668ab6..305be115319e 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -3721,10 +3721,12 @@ static void intel_crtc_disable(struct drm_crtc *crtc) struct drm_device *dev = crtc->dev; struct drm_connector *connector; struct drm_i915_private *dev_priv = dev->dev_private; + struct intel_crtc *intel_crtc = to_intel_crtc(crtc); /* crtc should still be enabled when we disable it. */ WARN_ON(!crtc->enabled); + intel_crtc->eld_vld = false; dev_priv->display.crtc_disable(crtc); intel_crtc_update_sarea(crtc, false); dev_priv->display.off(crtc); @@ -5792,6 +5794,7 @@ static void haswell_write_eld(struct drm_connector *connector, struct drm_i915_private *dev_priv = connector->dev->dev_private; uint8_t *eld = connector->eld; struct drm_device *dev = crtc->dev; + struct intel_crtc *intel_crtc = to_intel_crtc(crtc); uint32_t eldv; uint32_t i; int len; @@ -5833,6 +5836,7 @@ static void haswell_write_eld(struct drm_connector *connector, DRM_DEBUG_DRIVER("ELD on pipe %c\n", pipe_name(pipe)); eldv = AUDIO_ELD_VALID_A << (pipe * 4); + intel_crtc->eld_vld = true; if (intel_pipe_has_type(crtc, INTEL_OUTPUT_DISPLAYPORT)) { DRM_DEBUG_DRIVER("ELD: DisplayPort detected\n"); diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index aeff0d1067ad..66619d80348f 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -211,6 +211,7 @@ struct intel_crtc { * some outputs connected to this crtc. */ bool active; + bool eld_vld; bool primary_disabled; /* is the crtc obscured by a plane? */ bool lowfreq_avail; struct intel_overlay *overlay; From c00db2463978ffab59d731773aae1a4f4e11d78c Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Tue, 22 Jan 2013 15:33:27 +0100 Subject: [PATCH 042/101] drm/i915: fixup sbi_read/write locking commit 09153000b8ca32a539a1207edebabd0d40b6c61b Author: Daniel Vetter Date: Wed Dec 12 14:06:44 2012 +0100 drm/i915: rework locking for intel_dpio|sbi_read|write reworked the locking around sbi_read/write functions for 3.8-fixes. But commit dde86e2db54545ef981b64805097a7b4c3156d6e Author: Paulo Zanoni Date: Sat Dec 1 12:04:25 2012 -0200 drm/i915: add lpt_init_pch_refcl Added new use-cases in the -next tree which has not been updated in the merge. Fix it up. Reported-by: Ben Widawsky Reviewed-by: Ben Widawsky Tested-by: Ben Widawsky Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_display.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 305be115319e..886124a720e9 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -4873,6 +4873,8 @@ static void lpt_init_pch_refclk(struct drm_device *dev) if (!has_vga) return; + mutex_lock(&dev_priv->dpio_lock); + /* XXX: Rip out SDV support once Haswell ships for real. */ if (IS_HASWELL(dev) && (dev->pci_device & 0xFF00) == 0x0C00) is_sdv = true; @@ -5015,6 +5017,8 @@ static void lpt_init_pch_refclk(struct drm_device *dev) tmp = intel_sbi_read(dev_priv, SBI_DBUFF0, SBI_ICLK); tmp |= SBI_DBUFF0_ENABLE; intel_sbi_write(dev_priv, SBI_DBUFF0, tmp, SBI_ICLK); + + mutex_unlock(&dev_priv->dpio_lock); } /* From 8de0add7231f5747f192c1ed35fd792a866c885b Mon Sep 17 00:00:00 2001 From: Paulo Zanoni Date: Fri, 18 Jan 2013 18:29:03 -0200 Subject: [PATCH 043/101] drm/i915: don't save/restore DSPARB on gen5+ Because the register does not exist in gen5+. This patch solves "unclaimed register" messages on Haswell after suspend/resume. Signed-off-by: Paulo Zanoni Reviewed-by: Jani Nikula Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_suspend.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_suspend.c b/drivers/gpu/drm/i915/i915_suspend.c index 63d4d30c39de..95c0582eae77 100644 --- a/drivers/gpu/drm/i915/i915_suspend.c +++ b/drivers/gpu/drm/i915/i915_suspend.c @@ -620,7 +620,8 @@ static void i915_save_display(struct drm_device *dev) struct drm_i915_private *dev_priv = dev->dev_private; /* Display arbitration control */ - dev_priv->regfile.saveDSPARB = I915_READ(DSPARB); + if (INTEL_INFO(dev)->gen <= 4) + dev_priv->regfile.saveDSPARB = I915_READ(DSPARB); /* This is only meaningful in non-KMS mode */ /* Don't regfile.save them in KMS mode */ @@ -707,7 +708,8 @@ static void i915_restore_display(struct drm_device *dev) struct drm_i915_private *dev_priv = dev->dev_private; /* Display arbitration */ - I915_WRITE(DSPARB, dev_priv->regfile.saveDSPARB); + if (INTEL_INFO(dev)->gen <= 4) + I915_WRITE(DSPARB, dev_priv->regfile.saveDSPARB); if (!drm_core_check_feature(dev, DRIVER_MODESET)) { /* Display port ratios (must be done before clock is set) */ From 69fde0a6109eb04d4a32b6a205cff48e9058f16e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Thu, 24 Jan 2013 15:29:26 +0200 Subject: [PATCH 044/101] drm/i915: Convert intel_hdmi to enum port MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Use intel_dig_port->port rather than intel_hdmi->sdvox_erg. Signed-off-by: Ville Syrjälä Reviewed-by: Paulo Zanoni Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_hdmi.c | 27 +++++++++++++++------------ 1 file changed, 15 insertions(+), 12 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_hdmi.c b/drivers/gpu/drm/i915/intel_hdmi.c index d53b73131b0e..5b4efd64c2f9 100644 --- a/drivers/gpu/drm/i915/intel_hdmi.c +++ b/drivers/gpu/drm/i915/intel_hdmi.c @@ -372,7 +372,8 @@ static void g4x_set_infoframes(struct drm_encoder *encoder, struct drm_display_mode *adjusted_mode) { struct drm_i915_private *dev_priv = encoder->dev->dev_private; - struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(encoder); + struct intel_digital_port *intel_dig_port = enc_to_dig_port(encoder); + struct intel_hdmi *intel_hdmi = &intel_dig_port->hdmi; u32 reg = VIDEO_DIP_CTL; u32 val = I915_READ(reg); u32 port; @@ -399,11 +400,11 @@ static void g4x_set_infoframes(struct drm_encoder *encoder, return; } - switch (intel_hdmi->sdvox_reg) { - case SDVOB: + switch (intel_dig_port->port) { + case PORT_B: port = VIDEO_DIP_PORT_B; break; - case SDVOC: + case PORT_C: port = VIDEO_DIP_PORT_C; break; default: @@ -436,7 +437,8 @@ static void ibx_set_infoframes(struct drm_encoder *encoder, { struct drm_i915_private *dev_priv = encoder->dev->dev_private; struct intel_crtc *intel_crtc = to_intel_crtc(encoder->crtc); - struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(encoder); + struct intel_digital_port *intel_dig_port = enc_to_dig_port(encoder); + struct intel_hdmi *intel_hdmi = &intel_dig_port->hdmi; u32 reg = TVIDEO_DIP_CTL(intel_crtc->pipe); u32 val = I915_READ(reg); u32 port; @@ -455,14 +457,14 @@ static void ibx_set_infoframes(struct drm_encoder *encoder, return; } - switch (intel_hdmi->sdvox_reg) { - case HDMIB: + switch (intel_dig_port->port) { + case PORT_B: port = VIDEO_DIP_PORT_B; break; - case HDMIC: + case PORT_C: port = VIDEO_DIP_PORT_C; break; - case HDMID: + case PORT_D: port = VIDEO_DIP_PORT_D; break; default: @@ -795,13 +797,14 @@ static bool g4x_hdmi_connected(struct intel_hdmi *intel_hdmi) { struct drm_device *dev = intel_hdmi_to_dev(intel_hdmi); struct drm_i915_private *dev_priv = dev->dev_private; + struct intel_digital_port *intel_dig_port = hdmi_to_dig_port(intel_hdmi); uint32_t bit; - switch (intel_hdmi->sdvox_reg) { - case SDVOB: + switch (intel_dig_port->port) { + case PORT_B: bit = HDMIB_HOTPLUG_LIVE_STATUS; break; - case SDVOC: + case PORT_C: bit = HDMIC_HOTPLUG_LIVE_STATUS; break; default: From 34f2be46c4a4db47aafa1c9e79320723dda7b5e4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Thu, 24 Jan 2013 15:29:27 +0200 Subject: [PATCH 045/101] drm/i915: Convert intel_dp to enum port MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Use intel_dig_port->port rather than intel_dp->output_reg. Signed-off-by: Ville Syrjälä Reviewed-by: Paulo Zanoni Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_dp.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c index 1492706ed087..51fd79758368 100644 --- a/drivers/gpu/drm/i915/intel_dp.c +++ b/drivers/gpu/drm/i915/intel_dp.c @@ -2291,16 +2291,17 @@ g4x_dp_detect(struct intel_dp *intel_dp) { struct drm_device *dev = intel_dp_to_dev(intel_dp); struct drm_i915_private *dev_priv = dev->dev_private; + struct intel_digital_port *intel_dig_port = dp_to_dig_port(intel_dp); uint32_t bit; - switch (intel_dp->output_reg) { - case DP_B: + switch (intel_dig_port->port) { + case PORT_B: bit = DPB_HOTPLUG_LIVE_STATUS; break; - case DP_C: + case PORT_C: bit = DPC_HOTPLUG_LIVE_STATUS; break; - case DP_D: + case PORT_D: bit = DPD_HOTPLUG_LIVE_STATUS; break; default: From 10fce67a971775cfa906eb176e2772938c2aaaf3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Thu, 24 Jan 2013 15:29:28 +0200 Subject: [PATCH 046/101] drm/i915: Add display_display_mmio_offset to intel_device_info MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add an optional offset to intel_device_info, which will added to most display register offsets. Signed-off-by: Ville Syrjälä Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_drv.h | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 56ece50910a8..09753e56b6d0 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -337,6 +337,7 @@ struct drm_i915_gt_funcs { DEV_INFO_FLAG(has_llc) struct intel_device_info { + u32 display_mmio_offset; u8 gen; u8 is_mobile:1; u8 is_i85x:1; From f4ba9f81715ed0ba000750bf8586d097077ce910 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Thu, 24 Jan 2013 15:29:29 +0200 Subject: [PATCH 047/101] drm/i915: AUD_VID_DID needs an offset on VLV MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Ville Syrjälä Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_reg.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index 2521617b55da..7dd7adba5beb 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -4298,7 +4298,7 @@ #define GEN7_ROW_CHICKEN2_GT2 0xf4f4 #define DOP_CLOCK_GATING_DISABLE (1<<0) -#define G4X_AUD_VID_DID 0x62020 +#define G4X_AUD_VID_DID (dev_priv->info->display_mmio_offset + 0x62020) #define INTEL_AUDIO_DEVCL 0x808629FB #define INTEL_AUDIO_DEVBLC 0x80862801 #define INTEL_AUDIO_DEVCTG 0x80862802 From f12c47b279ad851f86026b2b142a81f6a63772b9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Thu, 24 Jan 2013 15:29:30 +0200 Subject: [PATCH 048/101] drm/i915: Per-pipe PP registers are for VLV only MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Ville Syrjälä Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_reg.h | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index 7dd7adba5beb..425ea99e80e8 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -3996,17 +3996,17 @@ #define LVDS_DETECTED (1 << 1) /* vlv has 2 sets of panel control regs. */ -#define PIPEA_PP_STATUS 0x61200 -#define PIPEA_PP_CONTROL 0x61204 -#define PIPEA_PP_ON_DELAYS 0x61208 -#define PIPEA_PP_OFF_DELAYS 0x6120c -#define PIPEA_PP_DIVISOR 0x61210 +#define PIPEA_PP_STATUS (VLV_DISPLAY_BASE + 0x61200) +#define PIPEA_PP_CONTROL (VLV_DISPLAY_BASE + 0x61204) +#define PIPEA_PP_ON_DELAYS (VLV_DISPLAY_BASE + 0x61208) +#define PIPEA_PP_OFF_DELAYS (VLV_DISPLAY_BASE + 0x6120c) +#define PIPEA_PP_DIVISOR (VLV_DISPLAY_BASE + 0x61210) -#define PIPEB_PP_STATUS 0x61300 -#define PIPEB_PP_CONTROL 0x61304 -#define PIPEB_PP_ON_DELAYS 0x61308 -#define PIPEB_PP_OFF_DELAYS 0x6130c -#define PIPEB_PP_DIVISOR 0x61310 +#define PIPEB_PP_STATUS (VLV_DISPLAY_BASE + 0x61300) +#define PIPEB_PP_CONTROL (VLV_DISPLAY_BASE + 0x61304) +#define PIPEB_PP_ON_DELAYS (VLV_DISPLAY_BASE + 0x61308) +#define PIPEB_PP_OFF_DELAYS (VLV_DISPLAY_BASE + 0x6130c) +#define PIPEB_PP_DIVISOR (VLV_DISPLAY_BASE + 0x61310) #define PCH_PP_STATUS 0xc7200 #define PCH_PP_CONTROL 0xc7204 From b906487c515711d79e31ceb9fe75738574b5c3a2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Thu, 24 Jan 2013 15:29:31 +0200 Subject: [PATCH 049/101] drm/i915: VLV_VIDEO_DIP_CTL is for VLV only MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Ville Syrjälä Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_reg.h | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index 425ea99e80e8..b97c67ee206a 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -3700,13 +3700,13 @@ #define TVIDEO_DIP_DATA(pipe) _PIPE(pipe, _VIDEO_DIP_DATA_A, _VIDEO_DIP_DATA_B) #define TVIDEO_DIP_GCP(pipe) _PIPE(pipe, _VIDEO_DIP_GCP_A, _VIDEO_DIP_GCP_B) -#define VLV_VIDEO_DIP_CTL_A 0x60200 -#define VLV_VIDEO_DIP_DATA_A 0x60208 -#define VLV_VIDEO_DIP_GDCP_PAYLOAD_A 0x60210 +#define VLV_VIDEO_DIP_CTL_A (VLV_DISPLAY_BASE + 0x60200) +#define VLV_VIDEO_DIP_DATA_A (VLV_DISPLAY_BASE + 0x60208) +#define VLV_VIDEO_DIP_GDCP_PAYLOAD_A (VLV_DISPLAY_BASE + 0x60210) -#define VLV_VIDEO_DIP_CTL_B 0x61170 -#define VLV_VIDEO_DIP_DATA_B 0x61174 -#define VLV_VIDEO_DIP_GDCP_PAYLOAD_B 0x61178 +#define VLV_VIDEO_DIP_CTL_B (VLV_DISPLAY_BASE + 0x61170) +#define VLV_VIDEO_DIP_DATA_B (VLV_DISPLAY_BASE + 0x61174) +#define VLV_VIDEO_DIP_GDCP_PAYLOAD_B (VLV_DISPLAY_BASE + 0x61178) #define VLV_TVIDEO_DIP_CTL(pipe) \ _PIPE(pipe, VLV_VIDEO_DIP_CTL_A, VLV_VIDEO_DIP_CTL_B) From aab17139a0eec686bad80579f7a5d6969c998392 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Thu, 24 Jan 2013 15:29:32 +0200 Subject: [PATCH 050/101] drm/i915: PIPE M/N registers need an offset on VLV MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Ville Syrjälä Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_reg.h | 32 ++++++++++++++++---------------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index b97c67ee206a..01324472f4c8 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -3269,41 +3269,41 @@ #define FDI_PLL_FREQ_DISABLE_COUNT_LIMIT_MASK 0xff -#define _PIPEA_DATA_M1 0x60030 +#define _PIPEA_DATA_M1 (dev_priv->info->display_mmio_offset + 0x60030) #define TU_SIZE(x) (((x)-1) << 25) /* default size 64 */ #define TU_SIZE_MASK 0x7e000000 #define PIPE_DATA_M1_OFFSET 0 -#define _PIPEA_DATA_N1 0x60034 +#define _PIPEA_DATA_N1 (dev_priv->info->display_mmio_offset + 0x60034) #define PIPE_DATA_N1_OFFSET 0 -#define _PIPEA_DATA_M2 0x60038 +#define _PIPEA_DATA_M2 (dev_priv->info->display_mmio_offset + 0x60038) #define PIPE_DATA_M2_OFFSET 0 -#define _PIPEA_DATA_N2 0x6003c +#define _PIPEA_DATA_N2 (dev_priv->info->display_mmio_offset + 0x6003c) #define PIPE_DATA_N2_OFFSET 0 -#define _PIPEA_LINK_M1 0x60040 +#define _PIPEA_LINK_M1 (dev_priv->info->display_mmio_offset + 0x60040) #define PIPE_LINK_M1_OFFSET 0 -#define _PIPEA_LINK_N1 0x60044 +#define _PIPEA_LINK_N1 (dev_priv->info->display_mmio_offset + 0x60044) #define PIPE_LINK_N1_OFFSET 0 -#define _PIPEA_LINK_M2 0x60048 +#define _PIPEA_LINK_M2 (dev_priv->info->display_mmio_offset + 0x60048) #define PIPE_LINK_M2_OFFSET 0 -#define _PIPEA_LINK_N2 0x6004c +#define _PIPEA_LINK_N2 (dev_priv->info->display_mmio_offset + 0x6004c) #define PIPE_LINK_N2_OFFSET 0 /* PIPEB timing regs are same start from 0x61000 */ -#define _PIPEB_DATA_M1 0x61030 -#define _PIPEB_DATA_N1 0x61034 +#define _PIPEB_DATA_M1 (dev_priv->info->display_mmio_offset + 0x61030) +#define _PIPEB_DATA_N1 (dev_priv->info->display_mmio_offset + 0x61034) -#define _PIPEB_DATA_M2 0x61038 -#define _PIPEB_DATA_N2 0x6103c +#define _PIPEB_DATA_M2 (dev_priv->info->display_mmio_offset + 0x61038) +#define _PIPEB_DATA_N2 (dev_priv->info->display_mmio_offset + 0x6103c) -#define _PIPEB_LINK_M1 0x61040 -#define _PIPEB_LINK_N1 0x61044 +#define _PIPEB_LINK_M1 (dev_priv->info->display_mmio_offset + 0x61040) +#define _PIPEB_LINK_N1 (dev_priv->info->display_mmio_offset + 0x61044) -#define _PIPEB_LINK_M2 0x61048 -#define _PIPEB_LINK_N2 0x6104c +#define _PIPEB_LINK_M2 (dev_priv->info->display_mmio_offset + 0x61048) +#define _PIPEB_LINK_N2 (dev_priv->info->display_mmio_offset + 0x6104c) #define PIPE_DATA_M1(tran) _TRANSCODER(tran, _PIPEA_DATA_M1, _PIPEB_DATA_M1) #define PIPE_DATA_N1(tran) _TRANSCODER(tran, _PIPEA_DATA_N1, _PIPEB_DATA_N1) From 895abf0c3c6923c4203630d2288bb1fbe39c39db Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Thu, 24 Jan 2013 15:29:35 +0200 Subject: [PATCH 051/101] drm/i915: Primary plane registers need an offset on VLV MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Ville Syrjälä Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_reg.h | 36 ++++++++++++++++----------------- 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index 01324472f4c8..37589cda2060 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -2982,7 +2982,7 @@ #define CURPOS_IVB(pipe) _PIPE(pipe, _CURAPOS, _CURBPOS_IVB) /* Display A control */ -#define _DSPACNTR 0x70180 +#define _DSPACNTR (dev_priv->info->display_mmio_offset + 0x70180) #define DISPLAY_PLANE_ENABLE (1<<31) #define DISPLAY_PLANE_DISABLE 0 #define DISPPLANE_GAMMA_ENABLE (1<<30) @@ -3015,14 +3015,14 @@ #define DISPPLANE_STEREO_POLARITY_SECOND (1<<18) #define DISPPLANE_TRICKLE_FEED_DISABLE (1<<14) /* Ironlake */ #define DISPPLANE_TILED (1<<10) -#define _DSPAADDR 0x70184 -#define _DSPASTRIDE 0x70188 -#define _DSPAPOS 0x7018C /* reserved */ -#define _DSPASIZE 0x70190 -#define _DSPASURF 0x7019C /* 965+ only */ -#define _DSPATILEOFF 0x701A4 /* 965+ only */ -#define _DSPAOFFSET 0x701A4 /* HSW */ -#define _DSPASURFLIVE 0x701AC +#define _DSPAADDR (dev_priv->info->display_mmio_offset + 0x70184) +#define _DSPASTRIDE (dev_priv->info->display_mmio_offset + 0x70188) +#define _DSPAPOS (dev_priv->info->display_mmio_offset + 0x7018C) /* reserved */ +#define _DSPASIZE (dev_priv->info->display_mmio_offset + 0x70190) +#define _DSPASURF (dev_priv->info->display_mmio_offset + 0x7019C) /* 965+ only */ +#define _DSPATILEOFF (dev_priv->info->display_mmio_offset + 0x701A4) /* 965+ only */ +#define _DSPAOFFSET (dev_priv->info->display_mmio_offset + 0x701A4) /* HSW */ +#define _DSPASURFLIVE (dev_priv->info->display_mmio_offset + 0x701AC) #define DSPCNTR(plane) _PIPE(plane, _DSPACNTR, _DSPBCNTR) #define DSPADDR(plane) _PIPE(plane, _DSPAADDR, _DSPBADDR) @@ -3068,19 +3068,19 @@ /* Display B control */ -#define _DSPBCNTR 0x71180 +#define _DSPBCNTR (dev_priv->info->display_mmio_offset + 0x71180) #define DISPPLANE_ALPHA_TRANS_ENABLE (1<<15) #define DISPPLANE_ALPHA_TRANS_DISABLE 0 #define DISPPLANE_SPRITE_ABOVE_DISPLAY 0 #define DISPPLANE_SPRITE_ABOVE_OVERLAY (1) -#define _DSPBADDR 0x71184 -#define _DSPBSTRIDE 0x71188 -#define _DSPBPOS 0x7118C -#define _DSPBSIZE 0x71190 -#define _DSPBSURF 0x7119C -#define _DSPBTILEOFF 0x711A4 -#define _DSPBOFFSET 0x711A4 -#define _DSPBSURFLIVE 0x711AC +#define _DSPBADDR (dev_priv->info->display_mmio_offset + 0x71184) +#define _DSPBSTRIDE (dev_priv->info->display_mmio_offset + 0x71188) +#define _DSPBPOS (dev_priv->info->display_mmio_offset + 0x7118C) +#define _DSPBSIZE (dev_priv->info->display_mmio_offset + 0x71190) +#define _DSPBSURF (dev_priv->info->display_mmio_offset + 0x7119C) +#define _DSPBTILEOFF (dev_priv->info->display_mmio_offset + 0x711A4) +#define _DSPBOFFSET (dev_priv->info->display_mmio_offset + 0x711A4) +#define _DSPBSURFLIVE (dev_priv->info->display_mmio_offset + 0x711AC) /* Sprite A control */ #define _DVSACNTR 0x72180 From 0c3870ee585f94650e36918cb29c7dd6b3f3c779 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Thu, 24 Jan 2013 15:29:36 +0200 Subject: [PATCH 052/101] drm/i915: Pipe registers need an offset on VLV MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Ville Syrjälä Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_reg.h | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index 37589cda2060..899c5adbbf67 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -2618,10 +2618,10 @@ /* Display & cursor control */ /* Pipe A */ -#define _PIPEADSL 0x70000 +#define _PIPEADSL (dev_priv->info->display_mmio_offset + 0x70000) #define DSL_LINEMASK_GEN2 0x00000fff #define DSL_LINEMASK_GEN3 0x00001fff -#define _PIPEACONF 0x70008 +#define _PIPEACONF (dev_priv->info->display_mmio_offset + 0x70008) #define PIPECONF_ENABLE (1<<31) #define PIPECONF_DISABLE 0 #define PIPECONF_DOUBLE_WIDE (1<<30) @@ -2662,7 +2662,7 @@ #define PIPECONF_DITHER_TYPE_ST1 (1<<2) #define PIPECONF_DITHER_TYPE_ST2 (2<<2) #define PIPECONF_DITHER_TYPE_TEMP (3<<2) -#define _PIPEASTAT 0x70024 +#define _PIPEASTAT (dev_priv->info->display_mmio_offset + 0x70024) #define PIPE_FIFO_UNDERRUN_STATUS (1UL<<31) #define SPRITE1_FLIPDONE_INT_EN_VLV (1UL<<30) #define PIPE_CRC_ERROR_ENABLE (1UL<<29) @@ -2923,10 +2923,10 @@ * } while (high1 != high2); * frame = (high1 << 8) | low1; */ -#define _PIPEAFRAMEHIGH 0x70040 +#define _PIPEAFRAMEHIGH (dev_priv->info->display_mmio_offset + 0x70040) #define PIPE_FRAME_HIGH_MASK 0x0000ffff #define PIPE_FRAME_HIGH_SHIFT 0 -#define _PIPEAFRAMEPIXEL 0x70044 +#define _PIPEAFRAMEPIXEL (dev_priv->info->display_mmio_offset + 0x70044) #define PIPE_FRAME_LOW_MASK 0xff000000 #define PIPE_FRAME_LOW_SHIFT 24 #define PIPE_PIXEL_MASK 0x00ffffff @@ -3058,11 +3058,11 @@ #define SWF32 0x7241c /* Pipe B */ -#define _PIPEBDSL 0x71000 -#define _PIPEBCONF 0x71008 -#define _PIPEBSTAT 0x71024 -#define _PIPEBFRAMEHIGH 0x71040 -#define _PIPEBFRAMEPIXEL 0x71044 +#define _PIPEBDSL (dev_priv->info->display_mmio_offset + 0x71000) +#define _PIPEBCONF (dev_priv->info->display_mmio_offset + 0x71008) +#define _PIPEBSTAT (dev_priv->info->display_mmio_offset + 0x71024) +#define _PIPEBFRAMEHIGH (dev_priv->info->display_mmio_offset + 0x71040) +#define _PIPEBFRAMEPIXEL (dev_priv->info->display_mmio_offset + 0x71044) #define _PIPEB_FRMCOUNT_GM45 0x71040 #define _PIPEB_FLIPCOUNT_GM45 0x71044 From 9dc33f31f2ed609eb77ddebb82f93c7cdf348879 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Thu, 24 Jan 2013 15:29:37 +0200 Subject: [PATCH 053/101] drm/i915: Cursor registers need an offset on VLV MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit CURSIZE is not present on VLV, so it was left out, as were the IVB specific cursor B registers. Signed-off-by: Ville Syrjälä Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_reg.h | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index 899c5adbbf67..896946812e74 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -2937,7 +2937,7 @@ #define PIPE_FRMCOUNT_GM45(pipe) _PIPE(pipe, _PIPEA_FRMCOUNT_GM45, _PIPEB_FRMCOUNT_GM45) /* Cursor A & B regs */ -#define _CURACNTR 0x70080 +#define _CURACNTR (dev_priv->info->display_mmio_offset + 0x70080) /* Old style CUR*CNTR flags (desktop 8xx) */ #define CURSOR_ENABLE 0x80000000 #define CURSOR_GAMMA_ENABLE 0x40000000 @@ -2958,16 +2958,16 @@ #define MCURSOR_PIPE_A 0x00 #define MCURSOR_PIPE_B (1 << 28) #define MCURSOR_GAMMA_ENABLE (1 << 26) -#define _CURABASE 0x70084 -#define _CURAPOS 0x70088 +#define _CURABASE (dev_priv->info->display_mmio_offset + 0x70084) +#define _CURAPOS (dev_priv->info->display_mmio_offset + 0x70088) #define CURSOR_POS_MASK 0x007FF #define CURSOR_POS_SIGN 0x8000 #define CURSOR_X_SHIFT 0 #define CURSOR_Y_SHIFT 16 #define CURSIZE 0x700a0 -#define _CURBCNTR 0x700c0 -#define _CURBBASE 0x700c4 -#define _CURBPOS 0x700c8 +#define _CURBCNTR (dev_priv->info->display_mmio_offset + 0x700c0) +#define _CURBBASE (dev_priv->info->display_mmio_offset + 0x700c4) +#define _CURBPOS (dev_priv->info->display_mmio_offset + 0x700c8) #define _CURBCNTR_IVB 0x71080 #define _CURBBASE_IVB 0x71084 From 8f6d8ee9f6884b8fea026b614d0475177975d066 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Thu, 24 Jan 2013 15:29:38 +0200 Subject: [PATCH 054/101] drm/i915: VLV_DDL is VLV only and needs an offset MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Ville Syrjälä Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_reg.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index 896946812e74..3540a06743ee 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -2773,13 +2773,13 @@ /* drain latency register values*/ #define DRAIN_LATENCY_PRECISION_32 32 #define DRAIN_LATENCY_PRECISION_16 16 -#define VLV_DDL1 0x70050 +#define VLV_DDL1 (VLV_DISPLAY_BASE + 0x70050) #define DDL_CURSORA_PRECISION_32 (1<<31) #define DDL_CURSORA_PRECISION_16 (0<<31) #define DDL_CURSORA_SHIFT 24 #define DDL_PLANEA_PRECISION_32 (1<<7) #define DDL_PLANEA_PRECISION_16 (0<<7) -#define VLV_DDL2 0x70054 +#define VLV_DDL2 (VLV_DISPLAY_BASE + 0x70054) #define DDL_CURSORB_PRECISION_32 (1<<31) #define DDL_CURSORB_PRECISION_16 (0<<31) #define DDL_CURSORB_SHIFT 24 From 90f7da3fb5c9988d2ce9e87a35446f8bc9aa5997 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Thu, 24 Jan 2013 15:29:39 +0200 Subject: [PATCH 055/101] drm/i915: DSPFW registers need an offset on VLV MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Ville Syrjälä Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_reg.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index 3540a06743ee..4f4b989a98ea 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -2749,7 +2749,7 @@ #define DSPARB_BEND_SHIFT 9 /* on 855 */ #define DSPARB_AEND_SHIFT 0 -#define DSPFW1 0x70034 +#define DSPFW1 (dev_priv->info->display_mmio_offset + 0x70034) #define DSPFW_SR_SHIFT 23 #define DSPFW_SR_MASK (0x1ff<<23) #define DSPFW_CURSORB_SHIFT 16 @@ -2757,11 +2757,11 @@ #define DSPFW_PLANEB_SHIFT 8 #define DSPFW_PLANEB_MASK (0x7f<<8) #define DSPFW_PLANEA_MASK (0x7f) -#define DSPFW2 0x70038 +#define DSPFW2 (dev_priv->info->display_mmio_offset + 0x70038) #define DSPFW_CURSORA_MASK 0x00003f00 #define DSPFW_CURSORA_SHIFT 8 #define DSPFW_PLANEC_MASK (0x7f) -#define DSPFW3 0x7003c +#define DSPFW3 (dev_priv->info->display_mmio_offset + 0x7003c) #define DSPFW_HPLL_SR_EN (1<<31) #define DSPFW_CURSOR_SR_SHIFT 24 #define PINEVIEW_SELF_REFRESH_EN (1<<30) From b41fbda15184e0b4c4e0c0c21737e4abcbaff955 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Thu, 24 Jan 2013 15:29:41 +0200 Subject: [PATCH 056/101] drm/i915: DPFLIPSTAT and DPINVGTT registers are VLV only and need an offset MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Ville Syrjälä Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_reg.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index 4f4b989a98ea..e7b13c251ffa 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -2707,7 +2707,7 @@ #define PIPEFRAMEPIXEL(pipe) _PIPE(pipe, _PIPEAFRAMEPIXEL, _PIPEBFRAMEPIXEL) #define PIPESTAT(pipe) _PIPE(pipe, _PIPEASTAT, _PIPEBSTAT) -#define VLV_DPFLIPSTAT 0x70028 +#define VLV_DPFLIPSTAT (VLV_DISPLAY_BASE + 0x70028) #define PIPEB_LINE_COMPARE_INT_EN (1<<29) #define PIPEB_HLINE_INT_EN (1<<28) #define PIPEB_VBLANK_INT_EN (1<<27) @@ -2721,7 +2721,7 @@ #define SPRITEA_FLIPDONE_INT_EN (1<<17) #define PLANEA_FLIPDONE_INT_EN (1<<16) -#define DPINVGTT 0x7002c /* VLV only */ +#define DPINVGTT (VLV_DISPLAY_BASE + 0x7002c) /* VLV only */ #define CURSORB_INVALID_GTT_INT_EN (1<<23) #define CURSORA_INVALID_GTT_INT_EN (1<<22) #define SPRITED_INVALID_GTT_INT_EN (1<<21) From 7e470abf5488c17b3ca5b5abbd7db12f338cec20 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Thu, 24 Jan 2013 15:29:43 +0200 Subject: [PATCH 057/101] drm/i915: Panel fitter registers need an offset on VLV MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Ville Syrjälä Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_reg.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index e7b13c251ffa..0bf70ae37be9 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -1858,7 +1858,7 @@ #define PP_DIVISOR 0x61210 /* Panel fitting */ -#define PFIT_CONTROL 0x61230 +#define PFIT_CONTROL (dev_priv->info->display_mmio_offset + 0x61230) #define PFIT_ENABLE (1 << 31) #define PFIT_PIPE_MASK (3 << 29) #define PFIT_PIPE_SHIFT 29 @@ -1876,7 +1876,7 @@ #define PFIT_SCALING_PROGRAMMED (1 << 26) #define PFIT_SCALING_PILLAR (2 << 26) #define PFIT_SCALING_LETTER (3 << 26) -#define PFIT_PGM_RATIOS 0x61234 +#define PFIT_PGM_RATIOS (dev_priv->info->display_mmio_offset + 0x61234) /* Pre-965 */ #define PFIT_VERT_SCALE_SHIFT 20 #define PFIT_VERT_SCALE_MASK 0xfff00000 @@ -1888,7 +1888,7 @@ #define PFIT_HORIZ_SCALE_SHIFT_965 0 #define PFIT_HORIZ_SCALE_MASK_965 0x00001fff -#define PFIT_AUTO_RATIOS 0x61238 +#define PFIT_AUTO_RATIOS (dev_priv->info->display_mmio_offset + 0x61238) /* Backlight control */ #define BLC_PWM_CTL2 0x61250 /* 965+ only */ From 67d62c57465e5da7647cb13ef567b80f6deb9a3c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Thu, 24 Jan 2013 15:29:44 +0200 Subject: [PATCH 058/101] drm/i915: PORT_HOTPLUG registers need an offset on VLV MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Ville Syrjälä Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_reg.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index 0bf70ae37be9..4807db614c48 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -1612,7 +1612,7 @@ /* Hotplug control (945+ only) */ -#define PORT_HOTPLUG_EN 0x61110 +#define PORT_HOTPLUG_EN (dev_priv->info->display_mmio_offset + 0x61110) #define HDMIB_HOTPLUG_INT_EN (1 << 29) #define DPB_HOTPLUG_INT_EN (1 << 29) #define HDMIC_HOTPLUG_INT_EN (1 << 28) @@ -1639,7 +1639,7 @@ #define CRT_HOTPLUG_DETECT_VOLTAGE_325MV (0 << 2) #define CRT_HOTPLUG_DETECT_VOLTAGE_475MV (1 << 2) -#define PORT_HOTPLUG_STAT 0x61114 +#define PORT_HOTPLUG_STAT (dev_priv->info->display_mmio_offset + 0x61114) /* HDMI/DP bits are gen4+ */ #define DPB_HOTPLUG_LIVE_STATUS (1 << 29) #define DPC_HOTPLUG_LIVE_STATUS (1 << 28) From 4e8e7eb70388c90a2d0ea2ccf951b11c3ec24b3e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Thu, 24 Jan 2013 15:29:46 +0200 Subject: [PATCH 059/101] drm/i915: Pipe timing registers need an offset on VLV MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Ville Syrjälä Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_reg.h | 36 ++++++++++++++++----------------- 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index 4807db614c48..2982a3baf0e6 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -1532,26 +1532,26 @@ */ /* Pipe A timing regs */ -#define _HTOTAL_A 0x60000 -#define _HBLANK_A 0x60004 -#define _HSYNC_A 0x60008 -#define _VTOTAL_A 0x6000c -#define _VBLANK_A 0x60010 -#define _VSYNC_A 0x60014 -#define _PIPEASRC 0x6001c -#define _BCLRPAT_A 0x60020 -#define _VSYNCSHIFT_A 0x60028 +#define _HTOTAL_A (dev_priv->info->display_mmio_offset + 0x60000) +#define _HBLANK_A (dev_priv->info->display_mmio_offset + 0x60004) +#define _HSYNC_A (dev_priv->info->display_mmio_offset + 0x60008) +#define _VTOTAL_A (dev_priv->info->display_mmio_offset + 0x6000c) +#define _VBLANK_A (dev_priv->info->display_mmio_offset + 0x60010) +#define _VSYNC_A (dev_priv->info->display_mmio_offset + 0x60014) +#define _PIPEASRC (dev_priv->info->display_mmio_offset + 0x6001c) +#define _BCLRPAT_A (dev_priv->info->display_mmio_offset + 0x60020) +#define _VSYNCSHIFT_A (dev_priv->info->display_mmio_offset + 0x60028) /* Pipe B timing regs */ -#define _HTOTAL_B 0x61000 -#define _HBLANK_B 0x61004 -#define _HSYNC_B 0x61008 -#define _VTOTAL_B 0x6100c -#define _VBLANK_B 0x61010 -#define _VSYNC_B 0x61014 -#define _PIPEBSRC 0x6101c -#define _BCLRPAT_B 0x61020 -#define _VSYNCSHIFT_B 0x61028 +#define _HTOTAL_B (dev_priv->info->display_mmio_offset + 0x61000) +#define _HBLANK_B (dev_priv->info->display_mmio_offset + 0x61004) +#define _HSYNC_B (dev_priv->info->display_mmio_offset + 0x61008) +#define _VTOTAL_B (dev_priv->info->display_mmio_offset + 0x6100c) +#define _VBLANK_B (dev_priv->info->display_mmio_offset + 0x61010) +#define _VSYNC_B (dev_priv->info->display_mmio_offset + 0x61014) +#define _PIPEBSRC (dev_priv->info->display_mmio_offset + 0x6101c) +#define _BCLRPAT_B (dev_priv->info->display_mmio_offset + 0x61020) +#define _VSYNCSHIFT_B (dev_priv->info->display_mmio_offset + 0x61028) #define HTOTAL(trans) _TRANSCODER(trans, _HTOTAL_A, _HTOTAL_B) From 4b0599854b5669fbbb6c8b9a9463b550718bda11 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Thu, 24 Jan 2013 15:29:47 +0200 Subject: [PATCH 060/101] drm/i915: Pipe palette registers need an offset on VLV MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Ville Syrjälä Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_reg.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index 2982a3baf0e6..693baf90db91 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -1166,8 +1166,8 @@ * Palette regs */ -#define _PALETTE_A 0x0a000 -#define _PALETTE_B 0x0a800 +#define _PALETTE_A (dev_priv->info->display_mmio_offset + 0xa000) +#define _PALETTE_B (dev_priv->info->display_mmio_offset + 0xa800) #define PALETTE(pipe) _PIPE(pipe, _PALETTE_A, _PALETTE_B) /* MCH MMIO space */ From d88b2270862087544dd5234d95976db51d8ee5bf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Thu, 24 Jan 2013 15:29:48 +0200 Subject: [PATCH 061/101] drm/i915: FB_BLC_SELF_VLV is VLV only and needs an offset MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Ville Syrjälä Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_reg.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index 693baf90db91..86c4ffa3c050 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -1159,7 +1159,7 @@ #define RAMCLK_GATE_D 0x6210 /* CRL only */ #define DEUC 0x6214 /* CRL only */ -#define FW_BLC_SELF_VLV 0x6500 +#define FW_BLC_SELF_VLV (VLV_DISPLAY_BASE + 0x6500) #define FW_CSPWRDWNEN (1<<15) /* From 07ec7ec55baec26a3b77d310b0399d2e20f0f67b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Thu, 24 Jan 2013 15:29:51 +0200 Subject: [PATCH 062/101] drm/i915: Make VLV_GUNIT_CLOCK_GATE register value more readable MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Instead of 0x18xxxx use (VLV_DISPLAY_BASE + xxxx). Signed-off-by: Ville Syrjälä Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_reg.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index 86c4ffa3c050..06a37a09245e 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -554,7 +554,7 @@ #define IIR 0x020a4 #define IMR 0x020a8 #define ISR 0x020ac -#define VLV_GUNIT_CLOCK_GATE 0x182060 +#define VLV_GUNIT_CLOCK_GATE (VLV_DISPLAY_BASE + 0x2060) #define GCFG_DIS (1<<8) #define VLV_IIR_RW 0x182084 #define VLV_IER 0x1820a0 From ff7630109978a800481a97d98acab70677c05259 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Thu, 24 Jan 2013 15:29:52 +0200 Subject: [PATCH 063/101] drm/i915: Spell out VLV_DISPLAY_BASE for interrupt registers MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Instead of 0x18xxxx use (VLV_DISPLAY_BASE + xxxx). Signed-off-by: Ville Syrjälä Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_reg.h | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index 06a37a09245e..f842dd9009c3 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -556,11 +556,11 @@ #define ISR 0x020ac #define VLV_GUNIT_CLOCK_GATE (VLV_DISPLAY_BASE + 0x2060) #define GCFG_DIS (1<<8) -#define VLV_IIR_RW 0x182084 -#define VLV_IER 0x1820a0 -#define VLV_IIR 0x1820a4 -#define VLV_IMR 0x1820a8 -#define VLV_ISR 0x1820ac +#define VLV_IIR_RW (VLV_DISPLAY_BASE + 0x2084) +#define VLV_IER (VLV_DISPLAY_BASE + 0x20a0) +#define VLV_IIR (VLV_DISPLAY_BASE + 0x20a4) +#define VLV_IMR (VLV_DISPLAY_BASE + 0x20a8) +#define VLV_ISR (VLV_DISPLAY_BASE + 0x20ac) #define I915_PIPE_CONTROL_NOTIFY_INTERRUPT (1<<18) #define I915_DISPLAY_PORT_INTERRUPT (1<<17) #define I915_RENDER_COMMAND_PARSER_ERROR_INTERRUPT (1<<15) From 54d9d493ce08a7b106336c7393a7f7d3f2b2d9c0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Thu, 24 Jan 2013 15:29:53 +0200 Subject: [PATCH 064/101] drm/i915: DPIO registers are VLV only and need an offset MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Ville Syrjälä Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_reg.h | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index f842dd9009c3..94a08b92ef13 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -336,17 +336,19 @@ * 0x801c/3c: core clock bits * 0x8048/68: low pass filter coefficients * 0x8100: fast clock controls + * + * DPIO is VLV only. */ -#define DPIO_PKT 0x2100 +#define DPIO_PKT (VLV_DISPLAY_BASE + 0x2100) #define DPIO_RID (0<<24) #define DPIO_OP_WRITE (1<<16) #define DPIO_OP_READ (0<<16) #define DPIO_PORTID (0x12<<8) #define DPIO_BYTE (0xf<<4) #define DPIO_BUSY (1<<0) /* status only */ -#define DPIO_DATA 0x2104 -#define DPIO_REG 0x2108 -#define DPIO_CTL 0x2110 +#define DPIO_DATA (VLV_DISPLAY_BASE + 0x2104) +#define DPIO_REG (VLV_DISPLAY_BASE + 0x2108) +#define DPIO_CTL (VLV_DISPLAY_BASE + 0x2110) #define DPIO_MODSEL1 (1<<3) /* if ref clk b == 27 */ #define DPIO_MODSEL0 (1<<2) /* if ref clk a == 27 */ #define DPIO_SFR_BYPASS (1<<1) From d811215004dbcc213e70eef94541aa10a2258aef Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Thu, 24 Jan 2013 15:29:55 +0200 Subject: [PATCH 065/101] drm/i915: GPIO/GMBUS registers need an offset on VLV MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit GPIO/GMBUS registers must be offset on VLV, so simply adjust gpio_mmio_base to include the correct offset. Signed-off-by: Ville Syrjälä Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_i2c.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/gpu/drm/i915/intel_i2c.c b/drivers/gpu/drm/i915/intel_i2c.c index 7f0904170963..acf8aec9ada7 100644 --- a/drivers/gpu/drm/i915/intel_i2c.c +++ b/drivers/gpu/drm/i915/intel_i2c.c @@ -515,6 +515,8 @@ int intel_setup_gmbus(struct drm_device *dev) if (HAS_PCH_SPLIT(dev)) dev_priv->gpio_mmio_base = PCH_GPIOA - GPIOA; + else if (IS_VALLEYVIEW(dev)) + dev_priv->gpio_mmio_base = VLV_DISPLAY_BASE; else dev_priv->gpio_mmio_base = 0; From fba5d532d16db812dabaa80fb7570820daa2707b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Thu, 24 Jan 2013 15:29:56 +0200 Subject: [PATCH 066/101] drm/i915: Set display_mmio_offset for VLV MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This will cause display registers to include the correct offset on VLV. Signed-off-by: Ville Syrjälä Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_drv.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/gpu/drm/i915/i915_drv.c b/drivers/gpu/drm/i915/i915_drv.c index 3ff8e73f4341..521a25376718 100644 --- a/drivers/gpu/drm/i915/i915_drv.c +++ b/drivers/gpu/drm/i915/i915_drv.c @@ -276,6 +276,7 @@ static const struct intel_device_info intel_valleyview_m_info = { .has_bsd_ring = 1, .has_blt_ring = 1, .is_valleyview = 1, + .display_mmio_offset = VLV_DISPLAY_BASE, }; static const struct intel_device_info intel_valleyview_d_info = { @@ -285,6 +286,7 @@ static const struct intel_device_info intel_valleyview_d_info = { .has_bsd_ring = 1, .has_blt_ring = 1, .is_valleyview = 1, + .display_mmio_offset = VLV_DISPLAY_BASE, }; static const struct intel_device_info intel_haswell_d_info = { From fc2de40986f5a35c02f06dea4221113b3a7a7c3c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Fri, 25 Jan 2013 21:44:41 +0200 Subject: [PATCH 067/101] drm/i915: PLL registers need an offset on VLV MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit v2: Dropped the clock gating registers Signed-off-by: Ville Syrjälä Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_reg.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index 94a08b92ef13..452cb18818dc 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -921,8 +921,8 @@ #define VGA1_PD_P1_DIV_2 (1 << 13) #define VGA1_PD_P1_SHIFT 8 #define VGA1_PD_P1_MASK (0x1f << 8) -#define _DPLL_A 0x06014 -#define _DPLL_B 0x06018 +#define _DPLL_A (dev_priv->info->display_mmio_offset + 0x6014) +#define _DPLL_B (dev_priv->info->display_mmio_offset + 0x6018) #define DPLL(pipe) _PIPE(pipe, _DPLL_A, _DPLL_B) #define DPLL_VCO_ENABLE (1 << 31) #define DPLL_DVO_HIGH_SPEED (1 << 30) @@ -981,7 +981,7 @@ #define SDVO_MULTIPLIER_MASK 0x000000ff #define SDVO_MULTIPLIER_SHIFT_HIRES 4 #define SDVO_MULTIPLIER_SHIFT_VGA 0 -#define _DPLL_A_MD 0x0601c /* 965+ only */ +#define _DPLL_A_MD (dev_priv->info->display_mmio_offset + 0x601c) /* 965+ only */ /* * UDI pixel divider, controlling how many pixels are stuffed into a packet. * @@ -1018,7 +1018,7 @@ */ #define DPLL_MD_VGA_UDI_MULTIPLIER_MASK 0x0000003f #define DPLL_MD_VGA_UDI_MULTIPLIER_SHIFT 0 -#define _DPLL_B_MD 0x06020 /* 965+ only */ +#define _DPLL_B_MD (dev_priv->info->display_mmio_offset + 0x6020) /* 965+ only */ #define DPLL_MD(pipe) _PIPE(pipe, _DPLL_A_MD, _DPLL_B_MD) #define _FPA0 0x06040 From ca54b8107f6ad8c161fa102920dd70dfef19cd2e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Fri, 25 Jan 2013 21:44:42 +0200 Subject: [PATCH 068/101] drm/i915: Always use adpa_reg MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Instead of using ADPA/VLV_ADPA/PCH_ADPA in various parts of intel_crt code, just use adpa_reg which always contains the correct value for the platform. Signed-off-by: Ville Syrjälä Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_crt.c | 29 +++++++++++++++-------------- 1 file changed, 15 insertions(+), 14 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_crt.c b/drivers/gpu/drm/i915/intel_crt.c index 71a5ebad14fb..68e79f32e100 100644 --- a/drivers/gpu/drm/i915/intel_crt.c +++ b/drivers/gpu/drm/i915/intel_crt.c @@ -267,27 +267,27 @@ static bool intel_ironlake_crt_detect_hotplug(struct drm_connector *connector) crt->force_hotplug_required = 0; - save_adpa = adpa = I915_READ(PCH_ADPA); + save_adpa = adpa = I915_READ(crt->adpa_reg); DRM_DEBUG_KMS("trigger hotplug detect cycle: adpa=0x%x\n", adpa); adpa |= ADPA_CRT_HOTPLUG_FORCE_TRIGGER; if (turn_off_dac) adpa &= ~ADPA_DAC_ENABLE; - I915_WRITE(PCH_ADPA, adpa); + I915_WRITE(crt->adpa_reg, adpa); - if (wait_for((I915_READ(PCH_ADPA) & ADPA_CRT_HOTPLUG_FORCE_TRIGGER) == 0, + if (wait_for((I915_READ(crt->adpa_reg) & ADPA_CRT_HOTPLUG_FORCE_TRIGGER) == 0, 1000)) DRM_DEBUG_KMS("timed out waiting for FORCE_TRIGGER"); if (turn_off_dac) { - I915_WRITE(PCH_ADPA, save_adpa); - POSTING_READ(PCH_ADPA); + I915_WRITE(crt->adpa_reg, save_adpa); + POSTING_READ(crt->adpa_reg); } } /* Check the status to see if both blue and green are on now */ - adpa = I915_READ(PCH_ADPA); + adpa = I915_READ(crt->adpa_reg); if ((adpa & ADPA_CRT_HOTPLUG_MONITOR_MASK) != 0) ret = true; else @@ -300,26 +300,27 @@ static bool intel_ironlake_crt_detect_hotplug(struct drm_connector *connector) static bool valleyview_crt_detect_hotplug(struct drm_connector *connector) { struct drm_device *dev = connector->dev; + struct intel_crt *crt = intel_attached_crt(connector); struct drm_i915_private *dev_priv = dev->dev_private; u32 adpa; bool ret; u32 save_adpa; - save_adpa = adpa = I915_READ(ADPA); + save_adpa = adpa = I915_READ(crt->adpa_reg); DRM_DEBUG_KMS("trigger hotplug detect cycle: adpa=0x%x\n", adpa); adpa |= ADPA_CRT_HOTPLUG_FORCE_TRIGGER; - I915_WRITE(ADPA, adpa); + I915_WRITE(crt->adpa_reg, adpa); - if (wait_for((I915_READ(ADPA) & ADPA_CRT_HOTPLUG_FORCE_TRIGGER) == 0, + if (wait_for((I915_READ(crt->adpa_reg) & ADPA_CRT_HOTPLUG_FORCE_TRIGGER) == 0, 1000)) { DRM_DEBUG_KMS("timed out waiting for FORCE_TRIGGER"); - I915_WRITE(ADPA, save_adpa); + I915_WRITE(crt->adpa_reg, save_adpa); } /* Check the status to see if both blue and green are on now */ - adpa = I915_READ(ADPA); + adpa = I915_READ(crt->adpa_reg); if ((adpa & ADPA_CRT_HOTPLUG_MONITOR_MASK) != 0) ret = true; else @@ -665,11 +666,11 @@ static void intel_crt_reset(struct drm_connector *connector) if (HAS_PCH_SPLIT(dev)) { u32 adpa; - adpa = I915_READ(PCH_ADPA); + adpa = I915_READ(crt->adpa_reg); adpa &= ~ADPA_CRT_HOTPLUG_MASK; adpa |= ADPA_HOTPLUG_BITS; - I915_WRITE(PCH_ADPA, adpa); - POSTING_READ(PCH_ADPA); + I915_WRITE(crt->adpa_reg, adpa); + POSTING_READ(crt->adpa_reg); DRM_DEBUG_KMS("pch crt adpa set to 0x%x\n", adpa); crt->force_hotplug_required = 1; From 9d5f78fbbf924492001ac7b2915537968906e517 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Fri, 25 Jan 2013 21:44:43 +0200 Subject: [PATCH 069/101] drm/i915: VLV doesn't have SDVO MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Don't call intel_sdvo_init() for VLV. Preserve the same behaviour as when intel_sdvo_init() would have returned false. Signed-off-by: Ville Syrjälä Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_display.c | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 886124a720e9..4c4fbc5f30fa 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -8227,18 +8227,13 @@ static void intel_setup_outputs(struct drm_device *dev) if (I915_READ(PCH_DP_D) & DP_DETECTED) intel_dp_init(dev, PCH_DP_D, PORT_D); } else if (IS_VALLEYVIEW(dev)) { - int found; - /* Check for built-in panel first. Shares lanes with HDMI on SDVOC */ if (I915_READ(DP_C) & DP_DETECTED) intel_dp_init(dev, DP_C, PORT_C); if (I915_READ(SDVOB) & PORT_DETECTED) { - /* SDVOB multiplex with HDMIB */ - found = intel_sdvo_init(dev, SDVOB, true); - if (!found) - intel_hdmi_init(dev, SDVOB, PORT_B); - if (!found && (I915_READ(DP_B) & DP_DETECTED)) + intel_hdmi_init(dev, SDVOB, PORT_B); + if (I915_READ(DP_B) & DP_DETECTED) intel_dp_init(dev, DP_B, PORT_B); } From 67cfc2032b516e44b972abe30209234343e1f145 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Fri, 25 Jan 2013 21:44:44 +0200 Subject: [PATCH 070/101] drm/i915: Pass VLV_DISPLAY_BASE + reg to intel_{hdmi, dp}_init on VLV MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When passing the DP/HDMI/SDVO registers to the encoder init functions, include the VLV specific offset in the value. v2: Resolved conflicts w/ VLV SDVO elimination Signed-off-by: Ville Syrjälä Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_display.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 4c4fbc5f30fa..c5997d260172 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -8228,17 +8228,17 @@ static void intel_setup_outputs(struct drm_device *dev) intel_dp_init(dev, PCH_DP_D, PORT_D); } else if (IS_VALLEYVIEW(dev)) { /* Check for built-in panel first. Shares lanes with HDMI on SDVOC */ - if (I915_READ(DP_C) & DP_DETECTED) - intel_dp_init(dev, DP_C, PORT_C); + if (I915_READ(VLV_DISPLAY_BASE + DP_C) & DP_DETECTED) + intel_dp_init(dev, VLV_DISPLAY_BASE + DP_C, PORT_C); - if (I915_READ(SDVOB) & PORT_DETECTED) { - intel_hdmi_init(dev, SDVOB, PORT_B); - if (I915_READ(DP_B) & DP_DETECTED) - intel_dp_init(dev, DP_B, PORT_B); + if (I915_READ(VLV_DISPLAY_BASE + SDVOB) & PORT_DETECTED) { + intel_hdmi_init(dev, VLV_DISPLAY_BASE + SDVOB, PORT_B); + if (I915_READ(VLV_DISPLAY_BASE + DP_B) & DP_DETECTED) + intel_dp_init(dev, VLV_DISPLAY_BASE + DP_B, PORT_B); } - if (I915_READ(SDVOC) & PORT_DETECTED) - intel_hdmi_init(dev, SDVOC, PORT_C); + if (I915_READ(VLV_DISPLAY_BASE + SDVOC) & PORT_DETECTED) + intel_hdmi_init(dev, VLV_DISPLAY_BASE + SDVOC, PORT_C); } else if (SUPPORTS_DIGITAL_OUTPUTS(dev)) { bool found = false; From 56a12a509296c87d6f149be86c6694d312b21d35 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Fri, 25 Jan 2013 21:44:45 +0200 Subject: [PATCH 071/101] drm/i915: Include display_mmio_offset in sequencer index/data registers MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit SR01 needs to be touched to disable VGA on non-UMS setups too. So the sequencer registers need to include the appripriate offset on VLV. Signed-off-by: Ville Syrjälä Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_reg.h | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index 452cb18818dc..5944b4b69031 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -141,9 +141,15 @@ #define VGA_MSR_MEM_EN (1<<1) #define VGA_MSR_CGA_MODE (1<<0) -#define VGA_SR_INDEX 0x3c4 +/* + * SR01 is the only VGA register touched on non-UMS setups. + * VLV doesn't do UMS, so the sequencer index/data registers + * are the only VGA registers which need to include + * display_mmio_offset. + */ +#define VGA_SR_INDEX (dev_priv->info->display_mmio_offset + 0x3c4) #define SR01 1 -#define VGA_SR_DATA 0x3c5 +#define VGA_SR_DATA (dev_priv->info->display_mmio_offset + 0x3c5) #define VGA_AR_INDEX 0x3c0 #define VGA_AR_VID_EN (1<<5) From 80a75f7c44c8fd8cf6b271dc20801846bd630349 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Thu, 24 Jan 2013 15:29:33 +0200 Subject: [PATCH 072/101] drm/i915: SWF screatch registers need an offset on VLV MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Ville Syrjälä Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_reg.h | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index 5944b4b69031..215443c378cc 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -3051,19 +3051,19 @@ (I915_WRITE((reg), (gfx_addr) | I915_LO_DISPBASE(I915_READ(reg)))) /* VBIOS flags */ -#define SWF00 0x71410 -#define SWF01 0x71414 -#define SWF02 0x71418 -#define SWF03 0x7141c -#define SWF04 0x71420 -#define SWF05 0x71424 -#define SWF06 0x71428 -#define SWF10 0x70410 -#define SWF11 0x70414 -#define SWF14 0x71420 -#define SWF30 0x72414 -#define SWF31 0x72418 -#define SWF32 0x7241c +#define SWF00 (dev_priv->info->display_mmio_offset + 0x71410) +#define SWF01 (dev_priv->info->display_mmio_offset + 0x71414) +#define SWF02 (dev_priv->info->display_mmio_offset + 0x71418) +#define SWF03 (dev_priv->info->display_mmio_offset + 0x7141c) +#define SWF04 (dev_priv->info->display_mmio_offset + 0x71420) +#define SWF05 (dev_priv->info->display_mmio_offset + 0x71424) +#define SWF06 (dev_priv->info->display_mmio_offset + 0x71428) +#define SWF10 (dev_priv->info->display_mmio_offset + 0x70410) +#define SWF11 (dev_priv->info->display_mmio_offset + 0x70414) +#define SWF14 (dev_priv->info->display_mmio_offset + 0x71420) +#define SWF30 (dev_priv->info->display_mmio_offset + 0x72414) +#define SWF31 (dev_priv->info->display_mmio_offset + 0x72418) +#define SWF32 (dev_priv->info->display_mmio_offset + 0x7241c) /* Pipe B */ #define _PIPEBDSL (dev_priv->info->display_mmio_offset + 0x71000) From fa42e23c1055a4549c433ac56ff869e441c973c8 Mon Sep 17 00:00:00 2001 From: Paulo Zanoni Date: Fri, 25 Jan 2013 16:59:11 -0200 Subject: [PATCH 073/101] drm/i915: fix intel_init_power_wells The current code was wrong in many different ways, so this is a full rewrite. We don't have "different power wells for different parts of the GPU", we have a single power well, but we have multiple registers that can be used to request enabling/disabling the power well. So let's be a good citizen and only use the register we're suppose to use, except when we're loading the driver, where we clear the request made by the BIOS. If any of the registers is requesting the power well to be enabled, it will be enabled. If none of the registers is requesting the power well to be enabled, it will be disabled. For now we're just forcing the power well to be enabled, but in the next commits we'll change this. V2: - Remove debug messages that could be misleading due to possible race conditions with KVMr, Debug and BIOS. - Don't wait on disabling: after a conversaion with a hardware engineer we discovered that the "restriction" on bit 31 is just for the "enable" case, and we don't even need to wait on the "disable" case. Signed-off-by: Paulo Zanoni Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_reg.h | 8 ++-- drivers/gpu/drm/i915/intel_display.c | 5 +-- drivers/gpu/drm/i915/intel_drv.h | 2 +- drivers/gpu/drm/i915/intel_pm.c | 59 +++++++++++++++++++--------- 4 files changed, 47 insertions(+), 27 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index 215443c378cc..a18218ccac1e 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -4422,10 +4422,10 @@ #define AUDIO_CP_READY_C (1<<9) /* HSW Power Wells */ -#define HSW_PWR_WELL_CTL1 0x45400 /* BIOS */ -#define HSW_PWR_WELL_CTL2 0x45404 /* Driver */ -#define HSW_PWR_WELL_CTL3 0x45408 /* KVMR */ -#define HSW_PWR_WELL_CTL4 0x4540C /* Debug */ +#define HSW_PWR_WELL_BIOS 0x45400 /* CTL1 */ +#define HSW_PWR_WELL_DRIVER 0x45404 /* CTL2 */ +#define HSW_PWR_WELL_KVMR 0x45408 /* CTL3 */ +#define HSW_PWR_WELL_DEBUG 0x4540C /* CTL4 */ #define HSW_PWR_WELL_ENABLE (1<<31) #define HSW_PWR_WELL_STATE (1<<30) #define HSW_PWR_WELL_CTL5 0x45410 diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index c5997d260172..19ab75f307e5 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -8659,10 +8659,7 @@ static void i915_disable_vga(struct drm_device *dev) void intel_modeset_init_hw(struct drm_device *dev) { - /* We attempt to init the necessary power wells early in the initialization - * time, so the subsystems that expect power to be enabled can work. - */ - intel_init_power_wells(dev); + intel_init_power_well(dev); intel_prepare_ddi(dev); diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index 66619d80348f..32c30423eaca 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -667,7 +667,7 @@ extern void intel_update_fbc(struct drm_device *dev); extern void intel_gpu_ips_init(struct drm_i915_private *dev_priv); extern void intel_gpu_ips_teardown(void); -extern void intel_init_power_wells(struct drm_device *dev); +extern void intel_init_power_well(struct drm_device *dev); extern void intel_enable_gt_powersave(struct drm_device *dev); extern void intel_disable_gt_powersave(struct drm_device *dev); extern void gen6_gt_check_fifodbg(struct drm_i915_private *dev_priv); diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c index 5a8a72c5a89d..b8cf16c06b1b 100644 --- a/drivers/gpu/drm/i915/intel_pm.c +++ b/drivers/gpu/drm/i915/intel_pm.c @@ -4043,33 +4043,56 @@ void intel_init_clock_gating(struct drm_device *dev) dev_priv->display.init_clock_gating(dev); } -/* Starting with Haswell, we have different power wells for - * different parts of the GPU. This attempts to enable them all. - */ -void intel_init_power_wells(struct drm_device *dev) +static void intel_set_power_well(struct drm_device *dev, bool enable) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + bool is_enabled, enable_requested; + uint32_t tmp; + + tmp = I915_READ(HSW_PWR_WELL_DRIVER); + is_enabled = tmp & HSW_PWR_WELL_STATE; + enable_requested = tmp & HSW_PWR_WELL_ENABLE; + + if (enable) { + if (!enable_requested) + I915_WRITE(HSW_PWR_WELL_DRIVER, HSW_PWR_WELL_ENABLE); + + if (!is_enabled) { + DRM_DEBUG_KMS("Enabling power well\n"); + if (wait_for((I915_READ(HSW_PWR_WELL_DRIVER) & + HSW_PWR_WELL_STATE), 20)) + DRM_ERROR("Timeout enabling power well\n"); + } + } else { + if (enable_requested) { + I915_WRITE(HSW_PWR_WELL_DRIVER, 0); + DRM_DEBUG_KMS("Requesting to disable the power well\n"); + } + } +} + +/* + * Starting with Haswell, we have a "Power Down Well" that can be turned off + * when not needed anymore. We have 4 registers that can request the power well + * to be enabled, and it will only be disabled if none of the registers is + * requesting it to be enabled. + */ +void intel_init_power_well(struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; - unsigned long power_wells[] = { - HSW_PWR_WELL_CTL1, - HSW_PWR_WELL_CTL2, - HSW_PWR_WELL_CTL4 - }; - int i; if (!IS_HASWELL(dev)) return; mutex_lock(&dev->struct_mutex); - for (i = 0; i < ARRAY_SIZE(power_wells); i++) { - int well = I915_READ(power_wells[i]); + /* For now, we need the power well to be always enabled. */ + intel_set_power_well(dev, true); - if ((well & HSW_PWR_WELL_STATE) == 0) { - I915_WRITE(power_wells[i], well & HSW_PWR_WELL_ENABLE); - if (wait_for((I915_READ(power_wells[i]) & HSW_PWR_WELL_STATE), 20)) - DRM_ERROR("Error enabling power well %lx\n", power_wells[i]); - } - } + /* We're taking over the BIOS, so clear any requests made by it since + * the driver is in charge now. */ + if (I915_READ(HSW_PWR_WELL_BIOS) & HSW_PWR_WELL_ENABLE) + I915_WRITE(HSW_PWR_WELL_BIOS, 0); mutex_unlock(&dev->struct_mutex); } From 56e5a3f043f0440cc0cce288e71134d1cb1b44a7 Mon Sep 17 00:00:00 2001 From: Paulo Zanoni Date: Fri, 25 Jan 2013 16:59:13 -0200 Subject: [PATCH 074/101] drm/i915: only disable enabled planes on intel_fb_restore_mode We should avoid touching registers that are on the power down well when we don't need to, because if we touch these registers when the power well is disabled we'll get tons of "unclaimed register" messages. This commit fixes some of these messages. Signed-off-by: Paulo Zanoni Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_fb.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/intel_fb.c b/drivers/gpu/drm/i915/intel_fb.c index ce5f54498426..6591029ac0d7 100644 --- a/drivers/gpu/drm/i915/intel_fb.c +++ b/drivers/gpu/drm/i915/intel_fb.c @@ -304,7 +304,8 @@ void intel_fb_restore_mode(struct drm_device *dev) /* Be sure to shut off any planes that may be active */ list_for_each_entry(plane, &config->plane_list, head) - plane->funcs->disable_plane(plane); + if (plane->enabled) + plane->funcs->disable_plane(plane); mutex_unlock(&dev->mode_config.mutex); } From cc464b2a17c59adedbdc02cc54341d630354edc3 Mon Sep 17 00:00:00 2001 From: Paulo Zanoni Date: Fri, 25 Jan 2013 16:59:16 -0200 Subject: [PATCH 075/101] drm/i915: set TRANSCODER_EDP even earlier Instead of setting it at the beginning of haswell_crtc_mode_set, let's set it at the beginning of intel_crtc_mode_set. When intel_crt_mode_set calls drm_vblank_pre_modeset we already need to have the transcoder_edp correctly set, because eventually drm_vblank_pre_modeset calls functions that call i915_pipe_enabled from i915_irq.c, which will read PIPECONF(cpu_transcoder). This is a bug that affects us since we added support for TRANSCODER_EDP, but I was only able to see the problem after suspending a machine with the power well disabled (got an "unclaimed register" error. Signed-off-by: Paulo Zanoni Reviewed-by: Jani Nikula Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_display.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 19ab75f307e5..c0fadf7686f7 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -5633,11 +5633,6 @@ static int haswell_crtc_mode_set(struct drm_crtc *crtc, num_connectors++; } - if (is_cpu_edp) - intel_crtc->cpu_transcoder = TRANSCODER_EDP; - else - intel_crtc->cpu_transcoder = pipe; - /* We are not sure yet this won't happen. */ WARN(!HAS_PCH_LPT(dev), "Unexpected PCH type %d\n", INTEL_PCH_TYPE(dev)); @@ -5702,6 +5697,11 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc, int pipe = intel_crtc->pipe; int ret; + if (IS_HASWELL(dev) && intel_pipe_has_type(crtc, INTEL_OUTPUT_EDP)) + intel_crtc->cpu_transcoder = TRANSCODER_EDP; + else + intel_crtc->cpu_transcoder = pipe; + drm_vblank_pre_modeset(dev, pipe); ret = dev_priv->display.crtc_mode_set(crtc, mode, adjusted_mode, From cb10799c194369633b183262edc75ec4b3e4e346 Mon Sep 17 00:00:00 2001 From: Paulo Zanoni Date: Fri, 25 Jan 2013 16:59:15 -0200 Subject: [PATCH 076/101] drm/i915: turn on the power well before suspending Our suspend code touches a lot of registers all over the place, so we need to enable the power well before suspending. Signed-off-by: Paulo Zanoni Reviewed-by: Jani Nikula [danvet: Fixup compilation by stealing the header decl from the dynamic power wells patch.] Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_drv.c | 2 ++ drivers/gpu/drm/i915/intel_drv.h | 1 + drivers/gpu/drm/i915/intel_pm.c | 2 +- 3 files changed, 4 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/i915_drv.c b/drivers/gpu/drm/i915/i915_drv.c index 521a25376718..9cc8f8780cf8 100644 --- a/drivers/gpu/drm/i915/i915_drv.c +++ b/drivers/gpu/drm/i915/i915_drv.c @@ -470,6 +470,8 @@ static int i915_drm_freeze(struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; + intel_set_power_well(dev, true); + drm_kms_helper_poll_disable(dev); pci_save_state(dev->pdev); diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index 32c30423eaca..fcdfe42e434c 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -668,6 +668,7 @@ extern void intel_gpu_ips_init(struct drm_i915_private *dev_priv); extern void intel_gpu_ips_teardown(void); extern void intel_init_power_well(struct drm_device *dev); +extern void intel_set_power_well(struct drm_device *dev, bool enable); extern void intel_enable_gt_powersave(struct drm_device *dev); extern void intel_disable_gt_powersave(struct drm_device *dev); extern void gen6_gt_check_fifodbg(struct drm_i915_private *dev_priv); diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c index b8cf16c06b1b..c97714e6a363 100644 --- a/drivers/gpu/drm/i915/intel_pm.c +++ b/drivers/gpu/drm/i915/intel_pm.c @@ -4043,7 +4043,7 @@ void intel_init_clock_gating(struct drm_device *dev) dev_priv->display.init_clock_gating(dev); } -static void intel_set_power_well(struct drm_device *dev, bool enable) +void intel_set_power_well(struct drm_device *dev, bool enable) { struct drm_i915_private *dev_priv = dev->dev_private; bool is_enabled, enable_requested; From 41c0b3a88c7bae96d8e2ee60c7ed91f57fd152d7 Mon Sep 17 00:00:00 2001 From: Ben Widawsky Date: Sat, 26 Jan 2013 11:52:00 -0800 Subject: [PATCH 077/101] drm/i915: Implement WaVSRefCountFullforceMissDisable MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Implements WaVSRefCountFullforceMissDisable as documented in the BSpec 3D workarounds chapter. Cc: Paulo Zanoni Signed-off-by: Ben Widawsky Reviewed-by: Ville Syrjälä Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_reg.h | 1 + drivers/gpu/drm/i915/intel_pm.c | 4 ++++ 2 files changed, 5 insertions(+) diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index a18218ccac1e..0c89cf5377ea 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -741,6 +741,7 @@ #define GEN7_FF_TS_SCHED_HS0 (0x3<<16) #define GEN7_FF_TS_SCHED_LOAD_BALANCE (0x1<<16) #define GEN7_FF_TS_SCHED_HW (0x0<<16) /* Default */ +#define GEN7_FF_VS_REF_CNT_FFME (1 << 15) #define GEN7_FF_VS_SCHED_HS1 (0x5<<12) #define GEN7_FF_VS_SCHED_HS0 (0x3<<12) #define GEN7_FF_VS_SCHED_LOAD_BALANCE (0x1<<12) /* Default */ diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c index c97714e6a363..64d65f564a7c 100644 --- a/drivers/gpu/drm/i915/intel_pm.c +++ b/drivers/gpu/drm/i915/intel_pm.c @@ -3680,6 +3680,10 @@ static void gen7_setup_fixed_func_scheduler(struct drm_i915_private *dev_priv) reg |= GEN7_FF_VS_SCHED_HW; reg |= GEN7_FF_DS_SCHED_HW; + /* WaVSRefCountFullforceMissDisable */ + if (IS_HASWELL(dev_priv->dev)) + reg &= ~GEN7_FF_VS_REF_CNT_FFME; + I915_WRITE(GEN7_FF_THREAD_MODE, reg); } From 2e9723a3e76a050f80064249dac644f86541d3b4 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Fri, 25 Jan 2013 17:53:19 +0100 Subject: [PATCH 078/101] drm/i915: move modeset checks out of save/restore_modeset_reg That way the control flow is clearer, and it prepares the stage to extract these ums functions and hide them somewhere. There's still tons of display stuff outside of these, but that requires more work. Reviewed-by: Imre Deak Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_suspend.c | 38 ++++++++++++----------------- 1 file changed, 15 insertions(+), 23 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_suspend.c b/drivers/gpu/drm/i915/i915_suspend.c index 95c0582eae77..bcde494b3805 100644 --- a/drivers/gpu/drm/i915/i915_suspend.c +++ b/drivers/gpu/drm/i915/i915_suspend.c @@ -240,9 +240,6 @@ static void i915_save_modeset_reg(struct drm_device *dev) struct drm_i915_private *dev_priv = dev->dev_private; int i; - if (drm_core_check_feature(dev, DRIVER_MODESET)) - return; - /* Cursor state */ dev_priv->regfile.saveCURACNTR = I915_READ(_CURACNTR); dev_priv->regfile.saveCURAPOS = I915_READ(_CURAPOS); @@ -410,8 +407,17 @@ static void i915_restore_modeset_reg(struct drm_device *dev) int dpll_b_reg, fpb0_reg, fpb1_reg; int i; - if (drm_core_check_feature(dev, DRIVER_MODESET)) - return; + /* Display port ratios (must be done before clock is set) */ + if (SUPPORTS_INTEGRATED_DP(dev)) { + I915_WRITE(_PIPEA_GMCH_DATA_M, dev_priv->regfile.savePIPEA_GMCH_DATA_M); + I915_WRITE(_PIPEB_GMCH_DATA_M, dev_priv->regfile.savePIPEB_GMCH_DATA_M); + I915_WRITE(_PIPEA_GMCH_DATA_N, dev_priv->regfile.savePIPEA_GMCH_DATA_N); + I915_WRITE(_PIPEB_GMCH_DATA_N, dev_priv->regfile.savePIPEB_GMCH_DATA_N); + I915_WRITE(_PIPEA_DP_LINK_M, dev_priv->regfile.savePIPEA_DP_LINK_M); + I915_WRITE(_PIPEB_DP_LINK_M, dev_priv->regfile.savePIPEB_DP_LINK_M); + I915_WRITE(_PIPEA_DP_LINK_N, dev_priv->regfile.savePIPEA_DP_LINK_N); + I915_WRITE(_PIPEB_DP_LINK_N, dev_priv->regfile.savePIPEB_DP_LINK_N); + } /* Fences */ switch (INTEL_INFO(dev)->gen) { @@ -625,7 +631,8 @@ static void i915_save_display(struct drm_device *dev) /* This is only meaningful in non-KMS mode */ /* Don't regfile.save them in KMS mode */ - i915_save_modeset_reg(dev); + if (!drm_core_check_feature(dev, DRIVER_MODESET)) + i915_save_modeset_reg(dev); /* LVDS state */ if (HAS_PCH_SPLIT(dev)) { @@ -711,23 +718,8 @@ static void i915_restore_display(struct drm_device *dev) if (INTEL_INFO(dev)->gen <= 4) I915_WRITE(DSPARB, dev_priv->regfile.saveDSPARB); - if (!drm_core_check_feature(dev, DRIVER_MODESET)) { - /* Display port ratios (must be done before clock is set) */ - if (SUPPORTS_INTEGRATED_DP(dev)) { - I915_WRITE(_PIPEA_GMCH_DATA_M, dev_priv->regfile.savePIPEA_GMCH_DATA_M); - I915_WRITE(_PIPEB_GMCH_DATA_M, dev_priv->regfile.savePIPEB_GMCH_DATA_M); - I915_WRITE(_PIPEA_GMCH_DATA_N, dev_priv->regfile.savePIPEA_GMCH_DATA_N); - I915_WRITE(_PIPEB_GMCH_DATA_N, dev_priv->regfile.savePIPEB_GMCH_DATA_N); - I915_WRITE(_PIPEA_DP_LINK_M, dev_priv->regfile.savePIPEA_DP_LINK_M); - I915_WRITE(_PIPEB_DP_LINK_M, dev_priv->regfile.savePIPEB_DP_LINK_M); - I915_WRITE(_PIPEA_DP_LINK_N, dev_priv->regfile.savePIPEA_DP_LINK_N); - I915_WRITE(_PIPEB_DP_LINK_N, dev_priv->regfile.savePIPEB_DP_LINK_N); - } - } - - /* This is only meaningful in non-KMS mode */ - /* Don't restore them in KMS mode */ - i915_restore_modeset_reg(dev); + if (!drm_core_check_feature(dev, DRIVER_MODESET)) + i915_restore_modeset_reg(dev); /* LVDS state */ if (INTEL_INFO(dev)->gen >= 4 && !HAS_PCH_SPLIT(dev)) From d8157a3687323ae5a76f1ecd0fc592b1d87be81b Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Fri, 25 Jan 2013 17:53:20 +0100 Subject: [PATCH 079/101] drm/i915: extract ums suspend/resume into i915_ums.c Similarly to how i915_dma.c is shaping up to be the dungeon hole for all things supporting dri1, create a new one to hide all the crazy things which are only really useful for ums support. Biggest part is the register suspend/resume support. Unfortunately a lot of it is still intermingled with bits and pieces we might still need, so needs more analysis and needs to stay in i915_suspend.c for now. Reviewed-by: Imre Deak v2: s/modeset_reg/display_reg/ as suggested by Imre, to avoid confusion between the kernel modeset code and display save/restore to support ums. v3: Fixup alphabetical order in the Makefile, spotted by Chris Wilson. Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/Makefile | 1 + drivers/gpu/drm/i915/i915_drv.h | 6 +- drivers/gpu/drm/i915/i915_suspend.c | 451 +------------------------- drivers/gpu/drm/i915/i915_ums.c | 479 ++++++++++++++++++++++++++++ 4 files changed, 485 insertions(+), 452 deletions(-) create mode 100644 drivers/gpu/drm/i915/i915_ums.c diff --git a/drivers/gpu/drm/i915/Makefile b/drivers/gpu/drm/i915/Makefile index 0f2c5493242b..91f3ac6cef35 100644 --- a/drivers/gpu/drm/i915/Makefile +++ b/drivers/gpu/drm/i915/Makefile @@ -16,6 +16,7 @@ i915-y := i915_drv.o i915_dma.o i915_irq.o \ i915_gem_tiling.o \ i915_sysfs.o \ i915_trace_points.o \ + i915_ums.o \ intel_display.o \ intel_crt.o \ intel_lvds.o \ diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 09753e56b6d0..a263a0c247fd 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -1730,9 +1730,9 @@ void i915_debugfs_cleanup(struct drm_minor *minor); extern int i915_save_state(struct drm_device *dev); extern int i915_restore_state(struct drm_device *dev); -/* i915_suspend.c */ -extern int i915_save_state(struct drm_device *dev); -extern int i915_restore_state(struct drm_device *dev); +/* i915_ums.c */ +void i915_save_display_reg(struct drm_device *dev); +void i915_restore_display_reg(struct drm_device *dev); /* i915_sysfs.c */ void i915_setup_sysfs(struct drm_device *dev_priv); diff --git a/drivers/gpu/drm/i915/i915_suspend.c b/drivers/gpu/drm/i915/i915_suspend.c index bcde494b3805..1f581fcb3120 100644 --- a/drivers/gpu/drm/i915/i915_suspend.c +++ b/drivers/gpu/drm/i915/i915_suspend.c @@ -29,67 +29,6 @@ #include "intel_drv.h" #include "i915_reg.h" -static bool i915_pipe_enabled(struct drm_device *dev, enum pipe pipe) -{ - struct drm_i915_private *dev_priv = dev->dev_private; - u32 dpll_reg; - - /* On IVB, 3rd pipe shares PLL with another one */ - if (pipe > 1) - return false; - - if (HAS_PCH_SPLIT(dev)) - dpll_reg = _PCH_DPLL(pipe); - else - dpll_reg = (pipe == PIPE_A) ? _DPLL_A : _DPLL_B; - - return (I915_READ(dpll_reg) & DPLL_VCO_ENABLE); -} - -static void i915_save_palette(struct drm_device *dev, enum pipe pipe) -{ - struct drm_i915_private *dev_priv = dev->dev_private; - unsigned long reg = (pipe == PIPE_A ? _PALETTE_A : _PALETTE_B); - u32 *array; - int i; - - if (!i915_pipe_enabled(dev, pipe)) - return; - - if (HAS_PCH_SPLIT(dev)) - reg = (pipe == PIPE_A) ? _LGC_PALETTE_A : _LGC_PALETTE_B; - - if (pipe == PIPE_A) - array = dev_priv->regfile.save_palette_a; - else - array = dev_priv->regfile.save_palette_b; - - for (i = 0; i < 256; i++) - array[i] = I915_READ(reg + (i << 2)); -} - -static void i915_restore_palette(struct drm_device *dev, enum pipe pipe) -{ - struct drm_i915_private *dev_priv = dev->dev_private; - unsigned long reg = (pipe == PIPE_A ? _PALETTE_A : _PALETTE_B); - u32 *array; - int i; - - if (!i915_pipe_enabled(dev, pipe)) - return; - - if (HAS_PCH_SPLIT(dev)) - reg = (pipe == PIPE_A) ? _LGC_PALETTE_A : _LGC_PALETTE_B; - - if (pipe == PIPE_A) - array = dev_priv->regfile.save_palette_a; - else - array = dev_priv->regfile.save_palette_b; - - for (i = 0; i < 256; i++) - I915_WRITE(reg + (i << 2), array[i]); -} - static u8 i915_read_indexed(struct drm_device *dev, u16 index_port, u16 data_port, u8 reg) { struct drm_i915_private *dev_priv = dev->dev_private; @@ -235,392 +174,6 @@ static void i915_restore_vga(struct drm_device *dev) I915_WRITE8(VGA_DACMASK, dev_priv->regfile.saveDACMASK); } -static void i915_save_modeset_reg(struct drm_device *dev) -{ - struct drm_i915_private *dev_priv = dev->dev_private; - int i; - - /* Cursor state */ - dev_priv->regfile.saveCURACNTR = I915_READ(_CURACNTR); - dev_priv->regfile.saveCURAPOS = I915_READ(_CURAPOS); - dev_priv->regfile.saveCURABASE = I915_READ(_CURABASE); - dev_priv->regfile.saveCURBCNTR = I915_READ(_CURBCNTR); - dev_priv->regfile.saveCURBPOS = I915_READ(_CURBPOS); - dev_priv->regfile.saveCURBBASE = I915_READ(_CURBBASE); - if (IS_GEN2(dev)) - dev_priv->regfile.saveCURSIZE = I915_READ(CURSIZE); - - if (HAS_PCH_SPLIT(dev)) { - dev_priv->regfile.savePCH_DREF_CONTROL = I915_READ(PCH_DREF_CONTROL); - dev_priv->regfile.saveDISP_ARB_CTL = I915_READ(DISP_ARB_CTL); - } - - /* Pipe & plane A info */ - dev_priv->regfile.savePIPEACONF = I915_READ(_PIPEACONF); - dev_priv->regfile.savePIPEASRC = I915_READ(_PIPEASRC); - if (HAS_PCH_SPLIT(dev)) { - dev_priv->regfile.saveFPA0 = I915_READ(_PCH_FPA0); - dev_priv->regfile.saveFPA1 = I915_READ(_PCH_FPA1); - dev_priv->regfile.saveDPLL_A = I915_READ(_PCH_DPLL_A); - } else { - dev_priv->regfile.saveFPA0 = I915_READ(_FPA0); - dev_priv->regfile.saveFPA1 = I915_READ(_FPA1); - dev_priv->regfile.saveDPLL_A = I915_READ(_DPLL_A); - } - if (INTEL_INFO(dev)->gen >= 4 && !HAS_PCH_SPLIT(dev)) - dev_priv->regfile.saveDPLL_A_MD = I915_READ(_DPLL_A_MD); - dev_priv->regfile.saveHTOTAL_A = I915_READ(_HTOTAL_A); - dev_priv->regfile.saveHBLANK_A = I915_READ(_HBLANK_A); - dev_priv->regfile.saveHSYNC_A = I915_READ(_HSYNC_A); - dev_priv->regfile.saveVTOTAL_A = I915_READ(_VTOTAL_A); - dev_priv->regfile.saveVBLANK_A = I915_READ(_VBLANK_A); - dev_priv->regfile.saveVSYNC_A = I915_READ(_VSYNC_A); - if (!HAS_PCH_SPLIT(dev)) - dev_priv->regfile.saveBCLRPAT_A = I915_READ(_BCLRPAT_A); - - if (HAS_PCH_SPLIT(dev)) { - dev_priv->regfile.savePIPEA_DATA_M1 = I915_READ(_PIPEA_DATA_M1); - dev_priv->regfile.savePIPEA_DATA_N1 = I915_READ(_PIPEA_DATA_N1); - dev_priv->regfile.savePIPEA_LINK_M1 = I915_READ(_PIPEA_LINK_M1); - dev_priv->regfile.savePIPEA_LINK_N1 = I915_READ(_PIPEA_LINK_N1); - - dev_priv->regfile.saveFDI_TXA_CTL = I915_READ(_FDI_TXA_CTL); - dev_priv->regfile.saveFDI_RXA_CTL = I915_READ(_FDI_RXA_CTL); - - dev_priv->regfile.savePFA_CTL_1 = I915_READ(_PFA_CTL_1); - dev_priv->regfile.savePFA_WIN_SZ = I915_READ(_PFA_WIN_SZ); - dev_priv->regfile.savePFA_WIN_POS = I915_READ(_PFA_WIN_POS); - - dev_priv->regfile.saveTRANSACONF = I915_READ(_TRANSACONF); - dev_priv->regfile.saveTRANS_HTOTAL_A = I915_READ(_TRANS_HTOTAL_A); - dev_priv->regfile.saveTRANS_HBLANK_A = I915_READ(_TRANS_HBLANK_A); - dev_priv->regfile.saveTRANS_HSYNC_A = I915_READ(_TRANS_HSYNC_A); - dev_priv->regfile.saveTRANS_VTOTAL_A = I915_READ(_TRANS_VTOTAL_A); - dev_priv->regfile.saveTRANS_VBLANK_A = I915_READ(_TRANS_VBLANK_A); - dev_priv->regfile.saveTRANS_VSYNC_A = I915_READ(_TRANS_VSYNC_A); - } - - dev_priv->regfile.saveDSPACNTR = I915_READ(_DSPACNTR); - dev_priv->regfile.saveDSPASTRIDE = I915_READ(_DSPASTRIDE); - dev_priv->regfile.saveDSPASIZE = I915_READ(_DSPASIZE); - dev_priv->regfile.saveDSPAPOS = I915_READ(_DSPAPOS); - dev_priv->regfile.saveDSPAADDR = I915_READ(_DSPAADDR); - if (INTEL_INFO(dev)->gen >= 4) { - dev_priv->regfile.saveDSPASURF = I915_READ(_DSPASURF); - dev_priv->regfile.saveDSPATILEOFF = I915_READ(_DSPATILEOFF); - } - i915_save_palette(dev, PIPE_A); - dev_priv->regfile.savePIPEASTAT = I915_READ(_PIPEASTAT); - - /* Pipe & plane B info */ - dev_priv->regfile.savePIPEBCONF = I915_READ(_PIPEBCONF); - dev_priv->regfile.savePIPEBSRC = I915_READ(_PIPEBSRC); - if (HAS_PCH_SPLIT(dev)) { - dev_priv->regfile.saveFPB0 = I915_READ(_PCH_FPB0); - dev_priv->regfile.saveFPB1 = I915_READ(_PCH_FPB1); - dev_priv->regfile.saveDPLL_B = I915_READ(_PCH_DPLL_B); - } else { - dev_priv->regfile.saveFPB0 = I915_READ(_FPB0); - dev_priv->regfile.saveFPB1 = I915_READ(_FPB1); - dev_priv->regfile.saveDPLL_B = I915_READ(_DPLL_B); - } - if (INTEL_INFO(dev)->gen >= 4 && !HAS_PCH_SPLIT(dev)) - dev_priv->regfile.saveDPLL_B_MD = I915_READ(_DPLL_B_MD); - dev_priv->regfile.saveHTOTAL_B = I915_READ(_HTOTAL_B); - dev_priv->regfile.saveHBLANK_B = I915_READ(_HBLANK_B); - dev_priv->regfile.saveHSYNC_B = I915_READ(_HSYNC_B); - dev_priv->regfile.saveVTOTAL_B = I915_READ(_VTOTAL_B); - dev_priv->regfile.saveVBLANK_B = I915_READ(_VBLANK_B); - dev_priv->regfile.saveVSYNC_B = I915_READ(_VSYNC_B); - if (!HAS_PCH_SPLIT(dev)) - dev_priv->regfile.saveBCLRPAT_B = I915_READ(_BCLRPAT_B); - - if (HAS_PCH_SPLIT(dev)) { - dev_priv->regfile.savePIPEB_DATA_M1 = I915_READ(_PIPEB_DATA_M1); - dev_priv->regfile.savePIPEB_DATA_N1 = I915_READ(_PIPEB_DATA_N1); - dev_priv->regfile.savePIPEB_LINK_M1 = I915_READ(_PIPEB_LINK_M1); - dev_priv->regfile.savePIPEB_LINK_N1 = I915_READ(_PIPEB_LINK_N1); - - dev_priv->regfile.saveFDI_TXB_CTL = I915_READ(_FDI_TXB_CTL); - dev_priv->regfile.saveFDI_RXB_CTL = I915_READ(_FDI_RXB_CTL); - - dev_priv->regfile.savePFB_CTL_1 = I915_READ(_PFB_CTL_1); - dev_priv->regfile.savePFB_WIN_SZ = I915_READ(_PFB_WIN_SZ); - dev_priv->regfile.savePFB_WIN_POS = I915_READ(_PFB_WIN_POS); - - dev_priv->regfile.saveTRANSBCONF = I915_READ(_TRANSBCONF); - dev_priv->regfile.saveTRANS_HTOTAL_B = I915_READ(_TRANS_HTOTAL_B); - dev_priv->regfile.saveTRANS_HBLANK_B = I915_READ(_TRANS_HBLANK_B); - dev_priv->regfile.saveTRANS_HSYNC_B = I915_READ(_TRANS_HSYNC_B); - dev_priv->regfile.saveTRANS_VTOTAL_B = I915_READ(_TRANS_VTOTAL_B); - dev_priv->regfile.saveTRANS_VBLANK_B = I915_READ(_TRANS_VBLANK_B); - dev_priv->regfile.saveTRANS_VSYNC_B = I915_READ(_TRANS_VSYNC_B); - } - - dev_priv->regfile.saveDSPBCNTR = I915_READ(_DSPBCNTR); - dev_priv->regfile.saveDSPBSTRIDE = I915_READ(_DSPBSTRIDE); - dev_priv->regfile.saveDSPBSIZE = I915_READ(_DSPBSIZE); - dev_priv->regfile.saveDSPBPOS = I915_READ(_DSPBPOS); - dev_priv->regfile.saveDSPBADDR = I915_READ(_DSPBADDR); - if (INTEL_INFO(dev)->gen >= 4) { - dev_priv->regfile.saveDSPBSURF = I915_READ(_DSPBSURF); - dev_priv->regfile.saveDSPBTILEOFF = I915_READ(_DSPBTILEOFF); - } - i915_save_palette(dev, PIPE_B); - dev_priv->regfile.savePIPEBSTAT = I915_READ(_PIPEBSTAT); - - /* Fences */ - switch (INTEL_INFO(dev)->gen) { - case 7: - case 6: - for (i = 0; i < 16; i++) - dev_priv->regfile.saveFENCE[i] = I915_READ64(FENCE_REG_SANDYBRIDGE_0 + (i * 8)); - break; - case 5: - case 4: - for (i = 0; i < 16; i++) - dev_priv->regfile.saveFENCE[i] = I915_READ64(FENCE_REG_965_0 + (i * 8)); - break; - case 3: - if (IS_I945G(dev) || IS_I945GM(dev) || IS_G33(dev)) - for (i = 0; i < 8; i++) - dev_priv->regfile.saveFENCE[i+8] = I915_READ(FENCE_REG_945_8 + (i * 4)); - case 2: - for (i = 0; i < 8; i++) - dev_priv->regfile.saveFENCE[i] = I915_READ(FENCE_REG_830_0 + (i * 4)); - break; - } - - /* CRT state */ - if (HAS_PCH_SPLIT(dev)) - dev_priv->regfile.saveADPA = I915_READ(PCH_ADPA); - else - dev_priv->regfile.saveADPA = I915_READ(ADPA); - - return; -} - -static void i915_restore_modeset_reg(struct drm_device *dev) -{ - struct drm_i915_private *dev_priv = dev->dev_private; - int dpll_a_reg, fpa0_reg, fpa1_reg; - int dpll_b_reg, fpb0_reg, fpb1_reg; - int i; - - /* Display port ratios (must be done before clock is set) */ - if (SUPPORTS_INTEGRATED_DP(dev)) { - I915_WRITE(_PIPEA_GMCH_DATA_M, dev_priv->regfile.savePIPEA_GMCH_DATA_M); - I915_WRITE(_PIPEB_GMCH_DATA_M, dev_priv->regfile.savePIPEB_GMCH_DATA_M); - I915_WRITE(_PIPEA_GMCH_DATA_N, dev_priv->regfile.savePIPEA_GMCH_DATA_N); - I915_WRITE(_PIPEB_GMCH_DATA_N, dev_priv->regfile.savePIPEB_GMCH_DATA_N); - I915_WRITE(_PIPEA_DP_LINK_M, dev_priv->regfile.savePIPEA_DP_LINK_M); - I915_WRITE(_PIPEB_DP_LINK_M, dev_priv->regfile.savePIPEB_DP_LINK_M); - I915_WRITE(_PIPEA_DP_LINK_N, dev_priv->regfile.savePIPEA_DP_LINK_N); - I915_WRITE(_PIPEB_DP_LINK_N, dev_priv->regfile.savePIPEB_DP_LINK_N); - } - - /* Fences */ - switch (INTEL_INFO(dev)->gen) { - case 7: - case 6: - for (i = 0; i < 16; i++) - I915_WRITE64(FENCE_REG_SANDYBRIDGE_0 + (i * 8), dev_priv->regfile.saveFENCE[i]); - break; - case 5: - case 4: - for (i = 0; i < 16; i++) - I915_WRITE64(FENCE_REG_965_0 + (i * 8), dev_priv->regfile.saveFENCE[i]); - break; - case 3: - case 2: - if (IS_I945G(dev) || IS_I945GM(dev) || IS_G33(dev)) - for (i = 0; i < 8; i++) - I915_WRITE(FENCE_REG_945_8 + (i * 4), dev_priv->regfile.saveFENCE[i+8]); - for (i = 0; i < 8; i++) - I915_WRITE(FENCE_REG_830_0 + (i * 4), dev_priv->regfile.saveFENCE[i]); - break; - } - - - if (HAS_PCH_SPLIT(dev)) { - dpll_a_reg = _PCH_DPLL_A; - dpll_b_reg = _PCH_DPLL_B; - fpa0_reg = _PCH_FPA0; - fpb0_reg = _PCH_FPB0; - fpa1_reg = _PCH_FPA1; - fpb1_reg = _PCH_FPB1; - } else { - dpll_a_reg = _DPLL_A; - dpll_b_reg = _DPLL_B; - fpa0_reg = _FPA0; - fpb0_reg = _FPB0; - fpa1_reg = _FPA1; - fpb1_reg = _FPB1; - } - - if (HAS_PCH_SPLIT(dev)) { - I915_WRITE(PCH_DREF_CONTROL, dev_priv->regfile.savePCH_DREF_CONTROL); - I915_WRITE(DISP_ARB_CTL, dev_priv->regfile.saveDISP_ARB_CTL); - } - - /* Pipe & plane A info */ - /* Prime the clock */ - if (dev_priv->regfile.saveDPLL_A & DPLL_VCO_ENABLE) { - I915_WRITE(dpll_a_reg, dev_priv->regfile.saveDPLL_A & - ~DPLL_VCO_ENABLE); - POSTING_READ(dpll_a_reg); - udelay(150); - } - I915_WRITE(fpa0_reg, dev_priv->regfile.saveFPA0); - I915_WRITE(fpa1_reg, dev_priv->regfile.saveFPA1); - /* Actually enable it */ - I915_WRITE(dpll_a_reg, dev_priv->regfile.saveDPLL_A); - POSTING_READ(dpll_a_reg); - udelay(150); - if (INTEL_INFO(dev)->gen >= 4 && !HAS_PCH_SPLIT(dev)) { - I915_WRITE(_DPLL_A_MD, dev_priv->regfile.saveDPLL_A_MD); - POSTING_READ(_DPLL_A_MD); - } - udelay(150); - - /* Restore mode */ - I915_WRITE(_HTOTAL_A, dev_priv->regfile.saveHTOTAL_A); - I915_WRITE(_HBLANK_A, dev_priv->regfile.saveHBLANK_A); - I915_WRITE(_HSYNC_A, dev_priv->regfile.saveHSYNC_A); - I915_WRITE(_VTOTAL_A, dev_priv->regfile.saveVTOTAL_A); - I915_WRITE(_VBLANK_A, dev_priv->regfile.saveVBLANK_A); - I915_WRITE(_VSYNC_A, dev_priv->regfile.saveVSYNC_A); - if (!HAS_PCH_SPLIT(dev)) - I915_WRITE(_BCLRPAT_A, dev_priv->regfile.saveBCLRPAT_A); - - if (HAS_PCH_SPLIT(dev)) { - I915_WRITE(_PIPEA_DATA_M1, dev_priv->regfile.savePIPEA_DATA_M1); - I915_WRITE(_PIPEA_DATA_N1, dev_priv->regfile.savePIPEA_DATA_N1); - I915_WRITE(_PIPEA_LINK_M1, dev_priv->regfile.savePIPEA_LINK_M1); - I915_WRITE(_PIPEA_LINK_N1, dev_priv->regfile.savePIPEA_LINK_N1); - - I915_WRITE(_FDI_RXA_CTL, dev_priv->regfile.saveFDI_RXA_CTL); - I915_WRITE(_FDI_TXA_CTL, dev_priv->regfile.saveFDI_TXA_CTL); - - I915_WRITE(_PFA_CTL_1, dev_priv->regfile.savePFA_CTL_1); - I915_WRITE(_PFA_WIN_SZ, dev_priv->regfile.savePFA_WIN_SZ); - I915_WRITE(_PFA_WIN_POS, dev_priv->regfile.savePFA_WIN_POS); - - I915_WRITE(_TRANSACONF, dev_priv->regfile.saveTRANSACONF); - I915_WRITE(_TRANS_HTOTAL_A, dev_priv->regfile.saveTRANS_HTOTAL_A); - I915_WRITE(_TRANS_HBLANK_A, dev_priv->regfile.saveTRANS_HBLANK_A); - I915_WRITE(_TRANS_HSYNC_A, dev_priv->regfile.saveTRANS_HSYNC_A); - I915_WRITE(_TRANS_VTOTAL_A, dev_priv->regfile.saveTRANS_VTOTAL_A); - I915_WRITE(_TRANS_VBLANK_A, dev_priv->regfile.saveTRANS_VBLANK_A); - I915_WRITE(_TRANS_VSYNC_A, dev_priv->regfile.saveTRANS_VSYNC_A); - } - - /* Restore plane info */ - I915_WRITE(_DSPASIZE, dev_priv->regfile.saveDSPASIZE); - I915_WRITE(_DSPAPOS, dev_priv->regfile.saveDSPAPOS); - I915_WRITE(_PIPEASRC, dev_priv->regfile.savePIPEASRC); - I915_WRITE(_DSPAADDR, dev_priv->regfile.saveDSPAADDR); - I915_WRITE(_DSPASTRIDE, dev_priv->regfile.saveDSPASTRIDE); - if (INTEL_INFO(dev)->gen >= 4) { - I915_WRITE(_DSPASURF, dev_priv->regfile.saveDSPASURF); - I915_WRITE(_DSPATILEOFF, dev_priv->regfile.saveDSPATILEOFF); - } - - I915_WRITE(_PIPEACONF, dev_priv->regfile.savePIPEACONF); - - i915_restore_palette(dev, PIPE_A); - /* Enable the plane */ - I915_WRITE(_DSPACNTR, dev_priv->regfile.saveDSPACNTR); - I915_WRITE(_DSPAADDR, I915_READ(_DSPAADDR)); - - /* Pipe & plane B info */ - if (dev_priv->regfile.saveDPLL_B & DPLL_VCO_ENABLE) { - I915_WRITE(dpll_b_reg, dev_priv->regfile.saveDPLL_B & - ~DPLL_VCO_ENABLE); - POSTING_READ(dpll_b_reg); - udelay(150); - } - I915_WRITE(fpb0_reg, dev_priv->regfile.saveFPB0); - I915_WRITE(fpb1_reg, dev_priv->regfile.saveFPB1); - /* Actually enable it */ - I915_WRITE(dpll_b_reg, dev_priv->regfile.saveDPLL_B); - POSTING_READ(dpll_b_reg); - udelay(150); - if (INTEL_INFO(dev)->gen >= 4 && !HAS_PCH_SPLIT(dev)) { - I915_WRITE(_DPLL_B_MD, dev_priv->regfile.saveDPLL_B_MD); - POSTING_READ(_DPLL_B_MD); - } - udelay(150); - - /* Restore mode */ - I915_WRITE(_HTOTAL_B, dev_priv->regfile.saveHTOTAL_B); - I915_WRITE(_HBLANK_B, dev_priv->regfile.saveHBLANK_B); - I915_WRITE(_HSYNC_B, dev_priv->regfile.saveHSYNC_B); - I915_WRITE(_VTOTAL_B, dev_priv->regfile.saveVTOTAL_B); - I915_WRITE(_VBLANK_B, dev_priv->regfile.saveVBLANK_B); - I915_WRITE(_VSYNC_B, dev_priv->regfile.saveVSYNC_B); - if (!HAS_PCH_SPLIT(dev)) - I915_WRITE(_BCLRPAT_B, dev_priv->regfile.saveBCLRPAT_B); - - if (HAS_PCH_SPLIT(dev)) { - I915_WRITE(_PIPEB_DATA_M1, dev_priv->regfile.savePIPEB_DATA_M1); - I915_WRITE(_PIPEB_DATA_N1, dev_priv->regfile.savePIPEB_DATA_N1); - I915_WRITE(_PIPEB_LINK_M1, dev_priv->regfile.savePIPEB_LINK_M1); - I915_WRITE(_PIPEB_LINK_N1, dev_priv->regfile.savePIPEB_LINK_N1); - - I915_WRITE(_FDI_RXB_CTL, dev_priv->regfile.saveFDI_RXB_CTL); - I915_WRITE(_FDI_TXB_CTL, dev_priv->regfile.saveFDI_TXB_CTL); - - I915_WRITE(_PFB_CTL_1, dev_priv->regfile.savePFB_CTL_1); - I915_WRITE(_PFB_WIN_SZ, dev_priv->regfile.savePFB_WIN_SZ); - I915_WRITE(_PFB_WIN_POS, dev_priv->regfile.savePFB_WIN_POS); - - I915_WRITE(_TRANSBCONF, dev_priv->regfile.saveTRANSBCONF); - I915_WRITE(_TRANS_HTOTAL_B, dev_priv->regfile.saveTRANS_HTOTAL_B); - I915_WRITE(_TRANS_HBLANK_B, dev_priv->regfile.saveTRANS_HBLANK_B); - I915_WRITE(_TRANS_HSYNC_B, dev_priv->regfile.saveTRANS_HSYNC_B); - I915_WRITE(_TRANS_VTOTAL_B, dev_priv->regfile.saveTRANS_VTOTAL_B); - I915_WRITE(_TRANS_VBLANK_B, dev_priv->regfile.saveTRANS_VBLANK_B); - I915_WRITE(_TRANS_VSYNC_B, dev_priv->regfile.saveTRANS_VSYNC_B); - } - - /* Restore plane info */ - I915_WRITE(_DSPBSIZE, dev_priv->regfile.saveDSPBSIZE); - I915_WRITE(_DSPBPOS, dev_priv->regfile.saveDSPBPOS); - I915_WRITE(_PIPEBSRC, dev_priv->regfile.savePIPEBSRC); - I915_WRITE(_DSPBADDR, dev_priv->regfile.saveDSPBADDR); - I915_WRITE(_DSPBSTRIDE, dev_priv->regfile.saveDSPBSTRIDE); - if (INTEL_INFO(dev)->gen >= 4) { - I915_WRITE(_DSPBSURF, dev_priv->regfile.saveDSPBSURF); - I915_WRITE(_DSPBTILEOFF, dev_priv->regfile.saveDSPBTILEOFF); - } - - I915_WRITE(_PIPEBCONF, dev_priv->regfile.savePIPEBCONF); - - i915_restore_palette(dev, PIPE_B); - /* Enable the plane */ - I915_WRITE(_DSPBCNTR, dev_priv->regfile.saveDSPBCNTR); - I915_WRITE(_DSPBADDR, I915_READ(_DSPBADDR)); - - /* Cursor state */ - I915_WRITE(_CURAPOS, dev_priv->regfile.saveCURAPOS); - I915_WRITE(_CURACNTR, dev_priv->regfile.saveCURACNTR); - I915_WRITE(_CURABASE, dev_priv->regfile.saveCURABASE); - I915_WRITE(_CURBPOS, dev_priv->regfile.saveCURBPOS); - I915_WRITE(_CURBCNTR, dev_priv->regfile.saveCURBCNTR); - I915_WRITE(_CURBBASE, dev_priv->regfile.saveCURBBASE); - if (IS_GEN2(dev)) - I915_WRITE(CURSIZE, dev_priv->regfile.saveCURSIZE); - - /* CRT state */ - if (HAS_PCH_SPLIT(dev)) - I915_WRITE(PCH_ADPA, dev_priv->regfile.saveADPA); - else - I915_WRITE(ADPA, dev_priv->regfile.saveADPA); - - return; -} - static void i915_save_display(struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; @@ -632,7 +185,7 @@ static void i915_save_display(struct drm_device *dev) /* This is only meaningful in non-KMS mode */ /* Don't regfile.save them in KMS mode */ if (!drm_core_check_feature(dev, DRIVER_MODESET)) - i915_save_modeset_reg(dev); + i915_save_display_reg(dev); /* LVDS state */ if (HAS_PCH_SPLIT(dev)) { @@ -719,7 +272,7 @@ static void i915_restore_display(struct drm_device *dev) I915_WRITE(DSPARB, dev_priv->regfile.saveDSPARB); if (!drm_core_check_feature(dev, DRIVER_MODESET)) - i915_restore_modeset_reg(dev); + i915_restore_display_reg(dev); /* LVDS state */ if (INTEL_INFO(dev)->gen >= 4 && !HAS_PCH_SPLIT(dev)) diff --git a/drivers/gpu/drm/i915/i915_ums.c b/drivers/gpu/drm/i915/i915_ums.c new file mode 100644 index 000000000000..359c77b7b1b2 --- /dev/null +++ b/drivers/gpu/drm/i915/i915_ums.c @@ -0,0 +1,479 @@ +/* + * + * Copyright 2008 (c) Intel Corporation + * Jesse Barnes + * Copyright 2013 (c) Intel Corporation + * Daniel Vetter + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sub license, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portions + * of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. + * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +#include +#include +#include "intel_drv.h" +#include "i915_reg.h" + +static bool i915_pipe_enabled(struct drm_device *dev, enum pipe pipe) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + u32 dpll_reg; + + /* On IVB, 3rd pipe shares PLL with another one */ + if (pipe > 1) + return false; + + if (HAS_PCH_SPLIT(dev)) + dpll_reg = _PCH_DPLL(pipe); + else + dpll_reg = (pipe == PIPE_A) ? _DPLL_A : _DPLL_B; + + return (I915_READ(dpll_reg) & DPLL_VCO_ENABLE); +} + +static void i915_save_palette(struct drm_device *dev, enum pipe pipe) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + unsigned long reg = (pipe == PIPE_A ? _PALETTE_A : _PALETTE_B); + u32 *array; + int i; + + if (!i915_pipe_enabled(dev, pipe)) + return; + + if (HAS_PCH_SPLIT(dev)) + reg = (pipe == PIPE_A) ? _LGC_PALETTE_A : _LGC_PALETTE_B; + + if (pipe == PIPE_A) + array = dev_priv->regfile.save_palette_a; + else + array = dev_priv->regfile.save_palette_b; + + for (i = 0; i < 256; i++) + array[i] = I915_READ(reg + (i << 2)); +} + +static void i915_restore_palette(struct drm_device *dev, enum pipe pipe) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + unsigned long reg = (pipe == PIPE_A ? _PALETTE_A : _PALETTE_B); + u32 *array; + int i; + + if (!i915_pipe_enabled(dev, pipe)) + return; + + if (HAS_PCH_SPLIT(dev)) + reg = (pipe == PIPE_A) ? _LGC_PALETTE_A : _LGC_PALETTE_B; + + if (pipe == PIPE_A) + array = dev_priv->regfile.save_palette_a; + else + array = dev_priv->regfile.save_palette_b; + + for (i = 0; i < 256; i++) + I915_WRITE(reg + (i << 2), array[i]); +} + +void i915_save_display_reg(struct drm_device *dev) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + int i; + + /* Cursor state */ + dev_priv->regfile.saveCURACNTR = I915_READ(_CURACNTR); + dev_priv->regfile.saveCURAPOS = I915_READ(_CURAPOS); + dev_priv->regfile.saveCURABASE = I915_READ(_CURABASE); + dev_priv->regfile.saveCURBCNTR = I915_READ(_CURBCNTR); + dev_priv->regfile.saveCURBPOS = I915_READ(_CURBPOS); + dev_priv->regfile.saveCURBBASE = I915_READ(_CURBBASE); + if (IS_GEN2(dev)) + dev_priv->regfile.saveCURSIZE = I915_READ(CURSIZE); + + if (HAS_PCH_SPLIT(dev)) { + dev_priv->regfile.savePCH_DREF_CONTROL = I915_READ(PCH_DREF_CONTROL); + dev_priv->regfile.saveDISP_ARB_CTL = I915_READ(DISP_ARB_CTL); + } + + /* Pipe & plane A info */ + dev_priv->regfile.savePIPEACONF = I915_READ(_PIPEACONF); + dev_priv->regfile.savePIPEASRC = I915_READ(_PIPEASRC); + if (HAS_PCH_SPLIT(dev)) { + dev_priv->regfile.saveFPA0 = I915_READ(_PCH_FPA0); + dev_priv->regfile.saveFPA1 = I915_READ(_PCH_FPA1); + dev_priv->regfile.saveDPLL_A = I915_READ(_PCH_DPLL_A); + } else { + dev_priv->regfile.saveFPA0 = I915_READ(_FPA0); + dev_priv->regfile.saveFPA1 = I915_READ(_FPA1); + dev_priv->regfile.saveDPLL_A = I915_READ(_DPLL_A); + } + if (INTEL_INFO(dev)->gen >= 4 && !HAS_PCH_SPLIT(dev)) + dev_priv->regfile.saveDPLL_A_MD = I915_READ(_DPLL_A_MD); + dev_priv->regfile.saveHTOTAL_A = I915_READ(_HTOTAL_A); + dev_priv->regfile.saveHBLANK_A = I915_READ(_HBLANK_A); + dev_priv->regfile.saveHSYNC_A = I915_READ(_HSYNC_A); + dev_priv->regfile.saveVTOTAL_A = I915_READ(_VTOTAL_A); + dev_priv->regfile.saveVBLANK_A = I915_READ(_VBLANK_A); + dev_priv->regfile.saveVSYNC_A = I915_READ(_VSYNC_A); + if (!HAS_PCH_SPLIT(dev)) + dev_priv->regfile.saveBCLRPAT_A = I915_READ(_BCLRPAT_A); + + if (HAS_PCH_SPLIT(dev)) { + dev_priv->regfile.savePIPEA_DATA_M1 = I915_READ(_PIPEA_DATA_M1); + dev_priv->regfile.savePIPEA_DATA_N1 = I915_READ(_PIPEA_DATA_N1); + dev_priv->regfile.savePIPEA_LINK_M1 = I915_READ(_PIPEA_LINK_M1); + dev_priv->regfile.savePIPEA_LINK_N1 = I915_READ(_PIPEA_LINK_N1); + + dev_priv->regfile.saveFDI_TXA_CTL = I915_READ(_FDI_TXA_CTL); + dev_priv->regfile.saveFDI_RXA_CTL = I915_READ(_FDI_RXA_CTL); + + dev_priv->regfile.savePFA_CTL_1 = I915_READ(_PFA_CTL_1); + dev_priv->regfile.savePFA_WIN_SZ = I915_READ(_PFA_WIN_SZ); + dev_priv->regfile.savePFA_WIN_POS = I915_READ(_PFA_WIN_POS); + + dev_priv->regfile.saveTRANSACONF = I915_READ(_TRANSACONF); + dev_priv->regfile.saveTRANS_HTOTAL_A = I915_READ(_TRANS_HTOTAL_A); + dev_priv->regfile.saveTRANS_HBLANK_A = I915_READ(_TRANS_HBLANK_A); + dev_priv->regfile.saveTRANS_HSYNC_A = I915_READ(_TRANS_HSYNC_A); + dev_priv->regfile.saveTRANS_VTOTAL_A = I915_READ(_TRANS_VTOTAL_A); + dev_priv->regfile.saveTRANS_VBLANK_A = I915_READ(_TRANS_VBLANK_A); + dev_priv->regfile.saveTRANS_VSYNC_A = I915_READ(_TRANS_VSYNC_A); + } + + dev_priv->regfile.saveDSPACNTR = I915_READ(_DSPACNTR); + dev_priv->regfile.saveDSPASTRIDE = I915_READ(_DSPASTRIDE); + dev_priv->regfile.saveDSPASIZE = I915_READ(_DSPASIZE); + dev_priv->regfile.saveDSPAPOS = I915_READ(_DSPAPOS); + dev_priv->regfile.saveDSPAADDR = I915_READ(_DSPAADDR); + if (INTEL_INFO(dev)->gen >= 4) { + dev_priv->regfile.saveDSPASURF = I915_READ(_DSPASURF); + dev_priv->regfile.saveDSPATILEOFF = I915_READ(_DSPATILEOFF); + } + i915_save_palette(dev, PIPE_A); + dev_priv->regfile.savePIPEASTAT = I915_READ(_PIPEASTAT); + + /* Pipe & plane B info */ + dev_priv->regfile.savePIPEBCONF = I915_READ(_PIPEBCONF); + dev_priv->regfile.savePIPEBSRC = I915_READ(_PIPEBSRC); + if (HAS_PCH_SPLIT(dev)) { + dev_priv->regfile.saveFPB0 = I915_READ(_PCH_FPB0); + dev_priv->regfile.saveFPB1 = I915_READ(_PCH_FPB1); + dev_priv->regfile.saveDPLL_B = I915_READ(_PCH_DPLL_B); + } else { + dev_priv->regfile.saveFPB0 = I915_READ(_FPB0); + dev_priv->regfile.saveFPB1 = I915_READ(_FPB1); + dev_priv->regfile.saveDPLL_B = I915_READ(_DPLL_B); + } + if (INTEL_INFO(dev)->gen >= 4 && !HAS_PCH_SPLIT(dev)) + dev_priv->regfile.saveDPLL_B_MD = I915_READ(_DPLL_B_MD); + dev_priv->regfile.saveHTOTAL_B = I915_READ(_HTOTAL_B); + dev_priv->regfile.saveHBLANK_B = I915_READ(_HBLANK_B); + dev_priv->regfile.saveHSYNC_B = I915_READ(_HSYNC_B); + dev_priv->regfile.saveVTOTAL_B = I915_READ(_VTOTAL_B); + dev_priv->regfile.saveVBLANK_B = I915_READ(_VBLANK_B); + dev_priv->regfile.saveVSYNC_B = I915_READ(_VSYNC_B); + if (!HAS_PCH_SPLIT(dev)) + dev_priv->regfile.saveBCLRPAT_B = I915_READ(_BCLRPAT_B); + + if (HAS_PCH_SPLIT(dev)) { + dev_priv->regfile.savePIPEB_DATA_M1 = I915_READ(_PIPEB_DATA_M1); + dev_priv->regfile.savePIPEB_DATA_N1 = I915_READ(_PIPEB_DATA_N1); + dev_priv->regfile.savePIPEB_LINK_M1 = I915_READ(_PIPEB_LINK_M1); + dev_priv->regfile.savePIPEB_LINK_N1 = I915_READ(_PIPEB_LINK_N1); + + dev_priv->regfile.saveFDI_TXB_CTL = I915_READ(_FDI_TXB_CTL); + dev_priv->regfile.saveFDI_RXB_CTL = I915_READ(_FDI_RXB_CTL); + + dev_priv->regfile.savePFB_CTL_1 = I915_READ(_PFB_CTL_1); + dev_priv->regfile.savePFB_WIN_SZ = I915_READ(_PFB_WIN_SZ); + dev_priv->regfile.savePFB_WIN_POS = I915_READ(_PFB_WIN_POS); + + dev_priv->regfile.saveTRANSBCONF = I915_READ(_TRANSBCONF); + dev_priv->regfile.saveTRANS_HTOTAL_B = I915_READ(_TRANS_HTOTAL_B); + dev_priv->regfile.saveTRANS_HBLANK_B = I915_READ(_TRANS_HBLANK_B); + dev_priv->regfile.saveTRANS_HSYNC_B = I915_READ(_TRANS_HSYNC_B); + dev_priv->regfile.saveTRANS_VTOTAL_B = I915_READ(_TRANS_VTOTAL_B); + dev_priv->regfile.saveTRANS_VBLANK_B = I915_READ(_TRANS_VBLANK_B); + dev_priv->regfile.saveTRANS_VSYNC_B = I915_READ(_TRANS_VSYNC_B); + } + + dev_priv->regfile.saveDSPBCNTR = I915_READ(_DSPBCNTR); + dev_priv->regfile.saveDSPBSTRIDE = I915_READ(_DSPBSTRIDE); + dev_priv->regfile.saveDSPBSIZE = I915_READ(_DSPBSIZE); + dev_priv->regfile.saveDSPBPOS = I915_READ(_DSPBPOS); + dev_priv->regfile.saveDSPBADDR = I915_READ(_DSPBADDR); + if (INTEL_INFO(dev)->gen >= 4) { + dev_priv->regfile.saveDSPBSURF = I915_READ(_DSPBSURF); + dev_priv->regfile.saveDSPBTILEOFF = I915_READ(_DSPBTILEOFF); + } + i915_save_palette(dev, PIPE_B); + dev_priv->regfile.savePIPEBSTAT = I915_READ(_PIPEBSTAT); + + /* Fences */ + switch (INTEL_INFO(dev)->gen) { + case 7: + case 6: + for (i = 0; i < 16; i++) + dev_priv->regfile.saveFENCE[i] = I915_READ64(FENCE_REG_SANDYBRIDGE_0 + (i * 8)); + break; + case 5: + case 4: + for (i = 0; i < 16; i++) + dev_priv->regfile.saveFENCE[i] = I915_READ64(FENCE_REG_965_0 + (i * 8)); + break; + case 3: + if (IS_I945G(dev) || IS_I945GM(dev) || IS_G33(dev)) + for (i = 0; i < 8; i++) + dev_priv->regfile.saveFENCE[i+8] = I915_READ(FENCE_REG_945_8 + (i * 4)); + case 2: + for (i = 0; i < 8; i++) + dev_priv->regfile.saveFENCE[i] = I915_READ(FENCE_REG_830_0 + (i * 4)); + break; + } + + /* CRT state */ + if (HAS_PCH_SPLIT(dev)) + dev_priv->regfile.saveADPA = I915_READ(PCH_ADPA); + else + dev_priv->regfile.saveADPA = I915_READ(ADPA); + + return; +} + +void i915_restore_display_reg(struct drm_device *dev) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + int dpll_a_reg, fpa0_reg, fpa1_reg; + int dpll_b_reg, fpb0_reg, fpb1_reg; + int i; + + /* Display port ratios (must be done before clock is set) */ + if (SUPPORTS_INTEGRATED_DP(dev)) { + I915_WRITE(_PIPEA_GMCH_DATA_M, dev_priv->regfile.savePIPEA_GMCH_DATA_M); + I915_WRITE(_PIPEB_GMCH_DATA_M, dev_priv->regfile.savePIPEB_GMCH_DATA_M); + I915_WRITE(_PIPEA_GMCH_DATA_N, dev_priv->regfile.savePIPEA_GMCH_DATA_N); + I915_WRITE(_PIPEB_GMCH_DATA_N, dev_priv->regfile.savePIPEB_GMCH_DATA_N); + I915_WRITE(_PIPEA_DP_LINK_M, dev_priv->regfile.savePIPEA_DP_LINK_M); + I915_WRITE(_PIPEB_DP_LINK_M, dev_priv->regfile.savePIPEB_DP_LINK_M); + I915_WRITE(_PIPEA_DP_LINK_N, dev_priv->regfile.savePIPEA_DP_LINK_N); + I915_WRITE(_PIPEB_DP_LINK_N, dev_priv->regfile.savePIPEB_DP_LINK_N); + } + + /* Fences */ + switch (INTEL_INFO(dev)->gen) { + case 7: + case 6: + for (i = 0; i < 16; i++) + I915_WRITE64(FENCE_REG_SANDYBRIDGE_0 + (i * 8), dev_priv->regfile.saveFENCE[i]); + break; + case 5: + case 4: + for (i = 0; i < 16; i++) + I915_WRITE64(FENCE_REG_965_0 + (i * 8), dev_priv->regfile.saveFENCE[i]); + break; + case 3: + case 2: + if (IS_I945G(dev) || IS_I945GM(dev) || IS_G33(dev)) + for (i = 0; i < 8; i++) + I915_WRITE(FENCE_REG_945_8 + (i * 4), dev_priv->regfile.saveFENCE[i+8]); + for (i = 0; i < 8; i++) + I915_WRITE(FENCE_REG_830_0 + (i * 4), dev_priv->regfile.saveFENCE[i]); + break; + } + + + if (HAS_PCH_SPLIT(dev)) { + dpll_a_reg = _PCH_DPLL_A; + dpll_b_reg = _PCH_DPLL_B; + fpa0_reg = _PCH_FPA0; + fpb0_reg = _PCH_FPB0; + fpa1_reg = _PCH_FPA1; + fpb1_reg = _PCH_FPB1; + } else { + dpll_a_reg = _DPLL_A; + dpll_b_reg = _DPLL_B; + fpa0_reg = _FPA0; + fpb0_reg = _FPB0; + fpa1_reg = _FPA1; + fpb1_reg = _FPB1; + } + + if (HAS_PCH_SPLIT(dev)) { + I915_WRITE(PCH_DREF_CONTROL, dev_priv->regfile.savePCH_DREF_CONTROL); + I915_WRITE(DISP_ARB_CTL, dev_priv->regfile.saveDISP_ARB_CTL); + } + + /* Pipe & plane A info */ + /* Prime the clock */ + if (dev_priv->regfile.saveDPLL_A & DPLL_VCO_ENABLE) { + I915_WRITE(dpll_a_reg, dev_priv->regfile.saveDPLL_A & + ~DPLL_VCO_ENABLE); + POSTING_READ(dpll_a_reg); + udelay(150); + } + I915_WRITE(fpa0_reg, dev_priv->regfile.saveFPA0); + I915_WRITE(fpa1_reg, dev_priv->regfile.saveFPA1); + /* Actually enable it */ + I915_WRITE(dpll_a_reg, dev_priv->regfile.saveDPLL_A); + POSTING_READ(dpll_a_reg); + udelay(150); + if (INTEL_INFO(dev)->gen >= 4 && !HAS_PCH_SPLIT(dev)) { + I915_WRITE(_DPLL_A_MD, dev_priv->regfile.saveDPLL_A_MD); + POSTING_READ(_DPLL_A_MD); + } + udelay(150); + + /* Restore mode */ + I915_WRITE(_HTOTAL_A, dev_priv->regfile.saveHTOTAL_A); + I915_WRITE(_HBLANK_A, dev_priv->regfile.saveHBLANK_A); + I915_WRITE(_HSYNC_A, dev_priv->regfile.saveHSYNC_A); + I915_WRITE(_VTOTAL_A, dev_priv->regfile.saveVTOTAL_A); + I915_WRITE(_VBLANK_A, dev_priv->regfile.saveVBLANK_A); + I915_WRITE(_VSYNC_A, dev_priv->regfile.saveVSYNC_A); + if (!HAS_PCH_SPLIT(dev)) + I915_WRITE(_BCLRPAT_A, dev_priv->regfile.saveBCLRPAT_A); + + if (HAS_PCH_SPLIT(dev)) { + I915_WRITE(_PIPEA_DATA_M1, dev_priv->regfile.savePIPEA_DATA_M1); + I915_WRITE(_PIPEA_DATA_N1, dev_priv->regfile.savePIPEA_DATA_N1); + I915_WRITE(_PIPEA_LINK_M1, dev_priv->regfile.savePIPEA_LINK_M1); + I915_WRITE(_PIPEA_LINK_N1, dev_priv->regfile.savePIPEA_LINK_N1); + + I915_WRITE(_FDI_RXA_CTL, dev_priv->regfile.saveFDI_RXA_CTL); + I915_WRITE(_FDI_TXA_CTL, dev_priv->regfile.saveFDI_TXA_CTL); + + I915_WRITE(_PFA_CTL_1, dev_priv->regfile.savePFA_CTL_1); + I915_WRITE(_PFA_WIN_SZ, dev_priv->regfile.savePFA_WIN_SZ); + I915_WRITE(_PFA_WIN_POS, dev_priv->regfile.savePFA_WIN_POS); + + I915_WRITE(_TRANSACONF, dev_priv->regfile.saveTRANSACONF); + I915_WRITE(_TRANS_HTOTAL_A, dev_priv->regfile.saveTRANS_HTOTAL_A); + I915_WRITE(_TRANS_HBLANK_A, dev_priv->regfile.saveTRANS_HBLANK_A); + I915_WRITE(_TRANS_HSYNC_A, dev_priv->regfile.saveTRANS_HSYNC_A); + I915_WRITE(_TRANS_VTOTAL_A, dev_priv->regfile.saveTRANS_VTOTAL_A); + I915_WRITE(_TRANS_VBLANK_A, dev_priv->regfile.saveTRANS_VBLANK_A); + I915_WRITE(_TRANS_VSYNC_A, dev_priv->regfile.saveTRANS_VSYNC_A); + } + + /* Restore plane info */ + I915_WRITE(_DSPASIZE, dev_priv->regfile.saveDSPASIZE); + I915_WRITE(_DSPAPOS, dev_priv->regfile.saveDSPAPOS); + I915_WRITE(_PIPEASRC, dev_priv->regfile.savePIPEASRC); + I915_WRITE(_DSPAADDR, dev_priv->regfile.saveDSPAADDR); + I915_WRITE(_DSPASTRIDE, dev_priv->regfile.saveDSPASTRIDE); + if (INTEL_INFO(dev)->gen >= 4) { + I915_WRITE(_DSPASURF, dev_priv->regfile.saveDSPASURF); + I915_WRITE(_DSPATILEOFF, dev_priv->regfile.saveDSPATILEOFF); + } + + I915_WRITE(_PIPEACONF, dev_priv->regfile.savePIPEACONF); + + i915_restore_palette(dev, PIPE_A); + /* Enable the plane */ + I915_WRITE(_DSPACNTR, dev_priv->regfile.saveDSPACNTR); + I915_WRITE(_DSPAADDR, I915_READ(_DSPAADDR)); + + /* Pipe & plane B info */ + if (dev_priv->regfile.saveDPLL_B & DPLL_VCO_ENABLE) { + I915_WRITE(dpll_b_reg, dev_priv->regfile.saveDPLL_B & + ~DPLL_VCO_ENABLE); + POSTING_READ(dpll_b_reg); + udelay(150); + } + I915_WRITE(fpb0_reg, dev_priv->regfile.saveFPB0); + I915_WRITE(fpb1_reg, dev_priv->regfile.saveFPB1); + /* Actually enable it */ + I915_WRITE(dpll_b_reg, dev_priv->regfile.saveDPLL_B); + POSTING_READ(dpll_b_reg); + udelay(150); + if (INTEL_INFO(dev)->gen >= 4 && !HAS_PCH_SPLIT(dev)) { + I915_WRITE(_DPLL_B_MD, dev_priv->regfile.saveDPLL_B_MD); + POSTING_READ(_DPLL_B_MD); + } + udelay(150); + + /* Restore mode */ + I915_WRITE(_HTOTAL_B, dev_priv->regfile.saveHTOTAL_B); + I915_WRITE(_HBLANK_B, dev_priv->regfile.saveHBLANK_B); + I915_WRITE(_HSYNC_B, dev_priv->regfile.saveHSYNC_B); + I915_WRITE(_VTOTAL_B, dev_priv->regfile.saveVTOTAL_B); + I915_WRITE(_VBLANK_B, dev_priv->regfile.saveVBLANK_B); + I915_WRITE(_VSYNC_B, dev_priv->regfile.saveVSYNC_B); + if (!HAS_PCH_SPLIT(dev)) + I915_WRITE(_BCLRPAT_B, dev_priv->regfile.saveBCLRPAT_B); + + if (HAS_PCH_SPLIT(dev)) { + I915_WRITE(_PIPEB_DATA_M1, dev_priv->regfile.savePIPEB_DATA_M1); + I915_WRITE(_PIPEB_DATA_N1, dev_priv->regfile.savePIPEB_DATA_N1); + I915_WRITE(_PIPEB_LINK_M1, dev_priv->regfile.savePIPEB_LINK_M1); + I915_WRITE(_PIPEB_LINK_N1, dev_priv->regfile.savePIPEB_LINK_N1); + + I915_WRITE(_FDI_RXB_CTL, dev_priv->regfile.saveFDI_RXB_CTL); + I915_WRITE(_FDI_TXB_CTL, dev_priv->regfile.saveFDI_TXB_CTL); + + I915_WRITE(_PFB_CTL_1, dev_priv->regfile.savePFB_CTL_1); + I915_WRITE(_PFB_WIN_SZ, dev_priv->regfile.savePFB_WIN_SZ); + I915_WRITE(_PFB_WIN_POS, dev_priv->regfile.savePFB_WIN_POS); + + I915_WRITE(_TRANSBCONF, dev_priv->regfile.saveTRANSBCONF); + I915_WRITE(_TRANS_HTOTAL_B, dev_priv->regfile.saveTRANS_HTOTAL_B); + I915_WRITE(_TRANS_HBLANK_B, dev_priv->regfile.saveTRANS_HBLANK_B); + I915_WRITE(_TRANS_HSYNC_B, dev_priv->regfile.saveTRANS_HSYNC_B); + I915_WRITE(_TRANS_VTOTAL_B, dev_priv->regfile.saveTRANS_VTOTAL_B); + I915_WRITE(_TRANS_VBLANK_B, dev_priv->regfile.saveTRANS_VBLANK_B); + I915_WRITE(_TRANS_VSYNC_B, dev_priv->regfile.saveTRANS_VSYNC_B); + } + + /* Restore plane info */ + I915_WRITE(_DSPBSIZE, dev_priv->regfile.saveDSPBSIZE); + I915_WRITE(_DSPBPOS, dev_priv->regfile.saveDSPBPOS); + I915_WRITE(_PIPEBSRC, dev_priv->regfile.savePIPEBSRC); + I915_WRITE(_DSPBADDR, dev_priv->regfile.saveDSPBADDR); + I915_WRITE(_DSPBSTRIDE, dev_priv->regfile.saveDSPBSTRIDE); + if (INTEL_INFO(dev)->gen >= 4) { + I915_WRITE(_DSPBSURF, dev_priv->regfile.saveDSPBSURF); + I915_WRITE(_DSPBTILEOFF, dev_priv->regfile.saveDSPBTILEOFF); + } + + I915_WRITE(_PIPEBCONF, dev_priv->regfile.savePIPEBCONF); + + i915_restore_palette(dev, PIPE_B); + /* Enable the plane */ + I915_WRITE(_DSPBCNTR, dev_priv->regfile.saveDSPBCNTR); + I915_WRITE(_DSPBADDR, I915_READ(_DSPBADDR)); + + /* Cursor state */ + I915_WRITE(_CURAPOS, dev_priv->regfile.saveCURAPOS); + I915_WRITE(_CURACNTR, dev_priv->regfile.saveCURACNTR); + I915_WRITE(_CURABASE, dev_priv->regfile.saveCURABASE); + I915_WRITE(_CURBPOS, dev_priv->regfile.saveCURBPOS); + I915_WRITE(_CURBCNTR, dev_priv->regfile.saveCURBCNTR); + I915_WRITE(_CURBBASE, dev_priv->regfile.saveCURBBASE); + if (IS_GEN2(dev)) + I915_WRITE(CURSIZE, dev_priv->regfile.saveCURSIZE); + + /* CRT state */ + if (HAS_PCH_SPLIT(dev)) + I915_WRITE(PCH_ADPA, dev_priv->regfile.saveADPA); + else + I915_WRITE(ADPA, dev_priv->regfile.saveADPA); + + return; +} From 44cec74040564cba2ace8c3756d2fc908bc7a373 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Fri, 25 Jan 2013 17:53:21 +0100 Subject: [PATCH 080/101] drm/i915: dont save/restore VGA state for kms The only thing we really care about that it is off. To do so, reuse the recently created i915_redisable_vga function, which is already used to put obnoxious firmware into check on lid reopening. Reviewed-by: Imre Deak Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_drv.h | 1 + drivers/gpu/drm/i915/i915_suspend.c | 48 +++++++++++++++------------- drivers/gpu/drm/i915/intel_display.c | 2 +- 3 files changed, 28 insertions(+), 23 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index a263a0c247fd..bffe222e1616 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -1789,6 +1789,7 @@ extern void intel_modeset_cleanup(struct drm_device *dev); extern int intel_modeset_vga_set_state(struct drm_device *dev, bool state); extern void intel_modeset_setup_hw_state(struct drm_device *dev, bool force_restore); +extern void i915_redisable_vga(struct drm_device *dev); extern bool intel_fbc_enabled(struct drm_device *dev); extern void intel_disable_fbc(struct drm_device *dev); extern bool ironlake_set_drps(struct drm_device *dev, u8 val); diff --git a/drivers/gpu/drm/i915/i915_suspend.c b/drivers/gpu/drm/i915/i915_suspend.c index 1f581fcb3120..3b9baea9a4c2 100644 --- a/drivers/gpu/drm/i915/i915_suspend.c +++ b/drivers/gpu/drm/i915/i915_suspend.c @@ -69,6 +69,15 @@ static void i915_save_vga(struct drm_device *dev) int i; u16 cr_index, cr_data, st01; + /* VGA state */ + dev_priv->regfile.saveVGA0 = I915_READ(VGA0); + dev_priv->regfile.saveVGA1 = I915_READ(VGA1); + dev_priv->regfile.saveVGA_PD = I915_READ(VGA_PD); + if (HAS_PCH_SPLIT(dev)) + dev_priv->regfile.saveVGACNTRL = I915_READ(CPU_VGACNTRL); + else + dev_priv->regfile.saveVGACNTRL = I915_READ(VGACNTRL); + /* VGA color palette registers */ dev_priv->regfile.saveDACMASK = I915_READ8(VGA_DACMASK); @@ -127,6 +136,18 @@ static void i915_restore_vga(struct drm_device *dev) int i; u16 cr_index, cr_data, st01; + /* VGA state */ + if (HAS_PCH_SPLIT(dev)) + I915_WRITE(CPU_VGACNTRL, dev_priv->regfile.saveVGACNTRL); + else + I915_WRITE(VGACNTRL, dev_priv->regfile.saveVGACNTRL); + + I915_WRITE(VGA0, dev_priv->regfile.saveVGA0); + I915_WRITE(VGA1, dev_priv->regfile.saveVGA1); + I915_WRITE(VGA_PD, dev_priv->regfile.saveVGA_PD); + POSTING_READ(VGA_PD); + udelay(150); + /* MSR bits */ I915_WRITE8(VGA_MSR_WRITE, dev_priv->regfile.saveMSR); if (dev_priv->regfile.saveMSR & VGA_MSR_CGA_MODE) { @@ -251,16 +272,8 @@ static void i915_save_display(struct drm_device *dev) } } - /* VGA state */ - dev_priv->regfile.saveVGA0 = I915_READ(VGA0); - dev_priv->regfile.saveVGA1 = I915_READ(VGA1); - dev_priv->regfile.saveVGA_PD = I915_READ(VGA_PD); - if (HAS_PCH_SPLIT(dev)) - dev_priv->regfile.saveVGACNTRL = I915_READ(CPU_VGACNTRL); - else - dev_priv->regfile.saveVGACNTRL = I915_READ(VGACNTRL); - - i915_save_vga(dev); + if (!drm_core_check_feature(dev, DRIVER_MODESET)) + i915_save_vga(dev); } static void i915_restore_display(struct drm_device *dev) @@ -334,19 +347,10 @@ static void i915_restore_display(struct drm_device *dev) I915_WRITE(FBC_CONTROL, dev_priv->regfile.saveFBC_CONTROL); } } - /* VGA state */ - if (HAS_PCH_SPLIT(dev)) - I915_WRITE(CPU_VGACNTRL, dev_priv->regfile.saveVGACNTRL); + if (!drm_core_check_feature(dev, DRIVER_MODESET)) + i915_restore_vga(dev); else - I915_WRITE(VGACNTRL, dev_priv->regfile.saveVGACNTRL); - - I915_WRITE(VGA0, dev_priv->regfile.saveVGA0); - I915_WRITE(VGA1, dev_priv->regfile.saveVGA1); - I915_WRITE(VGA_PD, dev_priv->regfile.saveVGA_PD); - POSTING_READ(VGA_PD); - udelay(150); - - i915_restore_vga(dev); + i915_redisable_vga(dev); } int i915_save_state(struct drm_device *dev) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index c0fadf7686f7..56c51ddf54ec 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -8903,7 +8903,7 @@ static void intel_sanitize_encoder(struct intel_encoder *encoder) * the crtc fixup. */ } -static void i915_redisable_vga(struct drm_device *dev) +void i915_redisable_vga(struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; u32 vga_reg; From a65e827dd57b2fd48a698209dd7701eb13e72095 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Fri, 25 Jan 2013 17:53:22 +0100 Subject: [PATCH 081/101] drm/i915: move DP save/restore into i915_ums.c Note that this slightly changes the order, but we only move it within the block of registers that restore encoder state. Specifically LVDS is now restored after DP, whereas previously it was done before. Legacy vga is still restored afterwards, which seems to be the important thing (if there's anything important in this restore ordering at all). Reviewed-by: Imre Deak Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_suspend.c | 29 +---------------------------- drivers/gpu/drm/i915/i915_ums.c | 24 ++++++++++++++++++++++++ 2 files changed, 25 insertions(+), 28 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_suspend.c b/drivers/gpu/drm/i915/i915_suspend.c index 3b9baea9a4c2..3911e0450bbe 100644 --- a/drivers/gpu/drm/i915/i915_suspend.c +++ b/drivers/gpu/drm/i915/i915_suspend.c @@ -240,24 +240,6 @@ static void i915_save_display(struct drm_device *dev) dev_priv->regfile.savePP_DIVISOR = I915_READ(PP_DIVISOR); } - if (!drm_core_check_feature(dev, DRIVER_MODESET)) { - /* Display Port state */ - if (SUPPORTS_INTEGRATED_DP(dev)) { - dev_priv->regfile.saveDP_B = I915_READ(DP_B); - dev_priv->regfile.saveDP_C = I915_READ(DP_C); - dev_priv->regfile.saveDP_D = I915_READ(DP_D); - dev_priv->regfile.savePIPEA_GMCH_DATA_M = I915_READ(_PIPEA_GMCH_DATA_M); - dev_priv->regfile.savePIPEB_GMCH_DATA_M = I915_READ(_PIPEB_GMCH_DATA_M); - dev_priv->regfile.savePIPEA_GMCH_DATA_N = I915_READ(_PIPEA_GMCH_DATA_N); - dev_priv->regfile.savePIPEB_GMCH_DATA_N = I915_READ(_PIPEB_GMCH_DATA_N); - dev_priv->regfile.savePIPEA_DP_LINK_M = I915_READ(_PIPEA_DP_LINK_M); - dev_priv->regfile.savePIPEB_DP_LINK_M = I915_READ(_PIPEB_DP_LINK_M); - dev_priv->regfile.savePIPEA_DP_LINK_N = I915_READ(_PIPEA_DP_LINK_N); - dev_priv->regfile.savePIPEB_DP_LINK_N = I915_READ(_PIPEB_DP_LINK_N); - } - /* FIXME: regfile.save TV & SDVO state */ - } - /* Only regfile.save FBC state on the platform that supports FBC */ if (I915_HAS_FBC(dev)) { if (HAS_PCH_SPLIT(dev)) { @@ -323,16 +305,6 @@ static void i915_restore_display(struct drm_device *dev) I915_WRITE(PP_CONTROL, dev_priv->regfile.savePP_CONTROL); } - if (!drm_core_check_feature(dev, DRIVER_MODESET)) { - /* Display Port state */ - if (SUPPORTS_INTEGRATED_DP(dev)) { - I915_WRITE(DP_B, dev_priv->regfile.saveDP_B); - I915_WRITE(DP_C, dev_priv->regfile.saveDP_C); - I915_WRITE(DP_D, dev_priv->regfile.saveDP_D); - } - /* FIXME: restore TV & SDVO state */ - } - /* only restore FBC info on the platform that supports FBC*/ intel_disable_fbc(dev); if (I915_HAS_FBC(dev)) { @@ -347,6 +319,7 @@ static void i915_restore_display(struct drm_device *dev) I915_WRITE(FBC_CONTROL, dev_priv->regfile.saveFBC_CONTROL); } } + if (!drm_core_check_feature(dev, DRIVER_MODESET)) i915_restore_vga(dev); else diff --git a/drivers/gpu/drm/i915/i915_ums.c b/drivers/gpu/drm/i915/i915_ums.c index 359c77b7b1b2..985a09716237 100644 --- a/drivers/gpu/drm/i915/i915_ums.c +++ b/drivers/gpu/drm/i915/i915_ums.c @@ -254,6 +254,22 @@ void i915_save_display_reg(struct drm_device *dev) else dev_priv->regfile.saveADPA = I915_READ(ADPA); + /* Display Port state */ + if (SUPPORTS_INTEGRATED_DP(dev)) { + dev_priv->regfile.saveDP_B = I915_READ(DP_B); + dev_priv->regfile.saveDP_C = I915_READ(DP_C); + dev_priv->regfile.saveDP_D = I915_READ(DP_D); + dev_priv->regfile.savePIPEA_GMCH_DATA_M = I915_READ(_PIPEA_GMCH_DATA_M); + dev_priv->regfile.savePIPEB_GMCH_DATA_M = I915_READ(_PIPEB_GMCH_DATA_M); + dev_priv->regfile.savePIPEA_GMCH_DATA_N = I915_READ(_PIPEA_GMCH_DATA_N); + dev_priv->regfile.savePIPEB_GMCH_DATA_N = I915_READ(_PIPEB_GMCH_DATA_N); + dev_priv->regfile.savePIPEA_DP_LINK_M = I915_READ(_PIPEA_DP_LINK_M); + dev_priv->regfile.savePIPEB_DP_LINK_M = I915_READ(_PIPEB_DP_LINK_M); + dev_priv->regfile.savePIPEA_DP_LINK_N = I915_READ(_PIPEA_DP_LINK_N); + dev_priv->regfile.savePIPEB_DP_LINK_N = I915_READ(_PIPEB_DP_LINK_N); + } + /* FIXME: regfile.save TV & SDVO state */ + return; } @@ -475,5 +491,13 @@ void i915_restore_display_reg(struct drm_device *dev) else I915_WRITE(ADPA, dev_priv->regfile.saveADPA); + /* Display Port state */ + if (SUPPORTS_INTEGRATED_DP(dev)) { + I915_WRITE(DP_B, dev_priv->regfile.saveDP_B); + I915_WRITE(DP_C, dev_priv->regfile.saveDP_C); + I915_WRITE(DP_D, dev_priv->regfile.saveDP_D); + } + /* FIXME: restore TV & SDVO state */ + return; } From 2f86f1916504525a6fdd6b412374b4ebf1102cbe Mon Sep 17 00:00:00 2001 From: Ben Widawsky Date: Mon, 28 Jan 2013 15:32:15 -0800 Subject: [PATCH 082/101] drm/i915: Error state should print /sys/kernel/debug /sys/kernel/debug has more or less been the standard location of debugfs for several years now. Other parts of DRM already use this location, so we should as well. Signed-off-by: Ben Widawsky Reviewed-by: Carl Worth Reviewed-by: Damien Lespiau [danvet: split up long line.] Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_irq.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c index 943db1001cfd..5648d846cdbf 100644 --- a/drivers/gpu/drm/i915/i915_irq.c +++ b/drivers/gpu/drm/i915/i915_irq.c @@ -1305,7 +1305,8 @@ static void i915_capture_error_state(struct drm_device *dev) return; } - DRM_INFO("capturing error event; look for more information in /debug/dri/%d/i915_error_state\n", + DRM_INFO("capturing error event; look for more information in" + "/sys/kernel/debug/dri/%d/i915_error_state\n", dev->primary->index); kref_init(&error->ref); From 7faf1ab2ff816d6ea9cde099e794a4e18cf13bbc Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Thu, 24 Jan 2013 14:44:55 -0800 Subject: [PATCH 083/101] drm/i915: vfuncs for gtt_clear_range/insert_entries We have a few too many differences here, so finally take the prepared abstraction and run with it. A few smaller changes are required to get things into shape: - move i915_cache_level up since we need it in the gt funcs - split up i915_ggtt_clear_range and move the two functions down to where the relevant insert_entries functions are - adjustments to a few function parameter lists Now we have 2 functions which deal with the gen6+ global gtt (gen6_ggtt_ prefix) and 2 functions which deal with the legacy gtt code in the intel-gtt.c fake agp driver (i915_ggtt_ prefix). Init is still a bit a mess, but honestly I don't care about that. One thing I've thought about while deciding on the exact interfaces is a flag parameter for ->clear_range: We could use that to decide between writing invalid pte entries or scratch pte entries. In case we ever get around to fixing all our bugs which currently prevent us from filling the gtt with empty ptes for the truly unused ranges ... Signed-off-by: Daniel Vetter [bwidawsk: Moved functions to the gtt struct] Signed-off-by: Ben Widawsky Reviewed-by: Damien Lespiau Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_drv.h | 21 +++-- drivers/gpu/drm/i915/i915_gem_gtt.c | 121 ++++++++++++++++------------ 2 files changed, 83 insertions(+), 59 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index bffe222e1616..fb0815bebe0f 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -365,6 +365,12 @@ struct intel_device_info { u8 has_llc:1; }; +enum i915_cache_level { + I915_CACHE_NONE = 0, + I915_CACHE_LLC, + I915_CACHE_LLC_MLC, /* gen6+, in docs at least! */ +}; + /* The Graphics Translation Table is the way in which GEN hardware translates a * Graphics Virtual Address into a Physical Address. In addition to the normal * collateral associated with any va->pa translations GEN hardware also has a @@ -386,6 +392,15 @@ struct i915_gtt { bool do_idle_maps; dma_addr_t scratch_page_dma; struct page *scratch_page; + + /* global gtt ops */ + void (*gtt_clear_range)(struct drm_device *dev, + unsigned int first_entry, + unsigned int num_entries); + void (*gtt_insert_entries)(struct drm_device *dev, + struct sg_table *st, + unsigned int pg_start, + enum i915_cache_level cache_level); }; #define I915_PPGTT_PD_ENTRIES 512 @@ -1023,12 +1038,6 @@ enum hdmi_force_audio { HDMI_AUDIO_ON, /* force turn on HDMI audio */ }; -enum i915_cache_level { - I915_CACHE_NONE = 0, - I915_CACHE_LLC, - I915_CACHE_LLC_MLC, /* gen6+, in docs at least! */ -}; - #define I915_GTT_RESERVED ((struct drm_mm_node *)0x1) struct drm_i915_gem_object_ops { diff --git a/drivers/gpu/drm/i915/i915_gem_gtt.c b/drivers/gpu/drm/i915/i915_gem_gtt.c index a0ba4a9e53c7..4712626f8dc1 100644 --- a/drivers/gpu/drm/i915/i915_gem_gtt.c +++ b/drivers/gpu/drm/i915/i915_gem_gtt.c @@ -367,40 +367,14 @@ static void undo_idling(struct drm_i915_private *dev_priv, bool interruptible) dev_priv->mm.interruptible = interruptible; } -static void i915_ggtt_clear_range(struct drm_device *dev, - unsigned first_entry, - unsigned num_entries) -{ - struct drm_i915_private *dev_priv = dev->dev_private; - gtt_pte_t scratch_pte; - gtt_pte_t __iomem *gtt_base = (gtt_pte_t __iomem *) dev_priv->gtt.gsm + first_entry; - const int max_entries = dev_priv->mm.gtt->gtt_total_entries - first_entry; - int i; - - if (INTEL_INFO(dev)->gen < 6) { - intel_gtt_clear_range(first_entry, num_entries); - return; - } - - if (WARN(num_entries > max_entries, - "First entry = %d; Num entries = %d (max=%d)\n", - first_entry, num_entries, max_entries)) - num_entries = max_entries; - - scratch_pte = pte_encode(dev, dev_priv->gtt.scratch_page_dma, I915_CACHE_LLC); - for (i = 0; i < num_entries; i++) - iowrite32(scratch_pte, >t_base[i]); - readl(gtt_base); -} - void i915_gem_restore_gtt_mappings(struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; struct drm_i915_gem_object *obj; /* First fill our portion of the GTT with scratch pages */ - i915_ggtt_clear_range(dev, dev_priv->gtt.start / PAGE_SIZE, - dev_priv->gtt.total / PAGE_SIZE); + dev_priv->gtt.gtt_clear_range(dev, dev_priv->gtt.start / PAGE_SIZE, + dev_priv->gtt.total / PAGE_SIZE); list_for_each_entry(obj, &dev_priv->mm.bound_list, gtt_list) { i915_gem_clflush_object(obj); @@ -429,15 +403,13 @@ int i915_gem_gtt_prepare_object(struct drm_i915_gem_object *obj) * within the global GTT as well as accessible by the GPU through the GMADR * mapped BAR (dev_priv->mm.gtt->gtt). */ -static void gen6_ggtt_bind_object(struct drm_i915_gem_object *obj, - enum i915_cache_level level) +static void gen6_ggtt_insert_entries(struct drm_device *dev, + struct sg_table *st, + unsigned int first_entry, + enum i915_cache_level level) { - struct drm_device *dev = obj->base.dev; struct drm_i915_private *dev_priv = dev->dev_private; - struct sg_table *st = obj->pages; struct scatterlist *sg = st->sgl; - const int first_entry = obj->gtt_space->start >> PAGE_SHIFT; - const int max_entries = dev_priv->mm.gtt->gtt_total_entries - first_entry; gtt_pte_t __iomem *gtt_entries = (gtt_pte_t __iomem *)dev_priv->gtt.gsm + first_entry; int unused, i = 0; @@ -453,9 +425,6 @@ static void gen6_ggtt_bind_object(struct drm_i915_gem_object *obj, } } - BUG_ON(i > max_entries); - BUG_ON(i != obj->base.size / PAGE_SIZE); - /* XXX: This serves as a posting read to make sure that the PTE has * actually been updated. There is some concern that even though * registers and PTEs are within the same BAR that they are potentially @@ -473,28 +442,69 @@ static void gen6_ggtt_bind_object(struct drm_i915_gem_object *obj, POSTING_READ(GFX_FLSH_CNTL_GEN6); } +static void gen6_ggtt_clear_range(struct drm_device *dev, + unsigned int first_entry, + unsigned int num_entries) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + gtt_pte_t scratch_pte; + gtt_pte_t __iomem *gtt_base = (gtt_pte_t __iomem *) dev_priv->gtt.gsm + first_entry; + const int max_entries = dev_priv->mm.gtt->gtt_total_entries - first_entry; + int i; + + if (WARN(num_entries > max_entries, + "First entry = %d; Num entries = %d (max=%d)\n", + first_entry, num_entries, max_entries)) + num_entries = max_entries; + + scratch_pte = pte_encode(dev, dev_priv->gtt.scratch_page_dma, I915_CACHE_LLC); + for (i = 0; i < num_entries; i++) + iowrite32(scratch_pte, >t_base[i]); + readl(gtt_base); +} + + +static void i915_ggtt_insert_entries(struct drm_device *dev, + struct sg_table *st, + unsigned int pg_start, + enum i915_cache_level cache_level) +{ + unsigned int flags = (cache_level == I915_CACHE_NONE) ? + AGP_USER_MEMORY : AGP_USER_CACHED_MEMORY; + + intel_gtt_insert_sg_entries(st, pg_start, flags); + +} + +static void i915_ggtt_clear_range(struct drm_device *dev, + unsigned int first_entry, + unsigned int num_entries) +{ + intel_gtt_clear_range(first_entry, num_entries); +} + + void i915_gem_gtt_bind_object(struct drm_i915_gem_object *obj, enum i915_cache_level cache_level) { struct drm_device *dev = obj->base.dev; - if (INTEL_INFO(dev)->gen < 6) { - unsigned int flags = (cache_level == I915_CACHE_NONE) ? - AGP_USER_MEMORY : AGP_USER_CACHED_MEMORY; - intel_gtt_insert_sg_entries(obj->pages, - obj->gtt_space->start >> PAGE_SHIFT, - flags); - } else { - gen6_ggtt_bind_object(obj, cache_level); - } + struct drm_i915_private *dev_priv = dev->dev_private; + + dev_priv->gtt.gtt_insert_entries(dev, obj->pages, + obj->gtt_space->start >> PAGE_SHIFT, + cache_level); obj->has_global_gtt_mapping = 1; } void i915_gem_gtt_unbind_object(struct drm_i915_gem_object *obj) { - i915_ggtt_clear_range(obj->base.dev, - obj->gtt_space->start >> PAGE_SHIFT, - obj->base.size >> PAGE_SHIFT); + struct drm_device *dev = obj->base.dev; + struct drm_i915_private *dev_priv = dev->dev_private; + + dev_priv->gtt.gtt_clear_range(obj->base.dev, + obj->gtt_space->start >> PAGE_SHIFT, + obj->base.size >> PAGE_SHIFT); obj->has_global_gtt_mapping = 0; } @@ -570,13 +580,12 @@ void i915_gem_setup_global_gtt(struct drm_device *dev, hole_start, hole_end) { DRM_DEBUG_KMS("clearing unused GTT space: [%lx, %lx]\n", hole_start, hole_end); - i915_ggtt_clear_range(dev, - hole_start / PAGE_SIZE, - (hole_end-hole_start) / PAGE_SIZE); + dev_priv->gtt.gtt_clear_range(dev, hole_start / PAGE_SIZE, + (hole_end-hole_start) / PAGE_SIZE); } /* And finally clear the reserved guard page */ - i915_ggtt_clear_range(dev, end / PAGE_SIZE - 1, 1); + dev_priv->gtt.gtt_clear_range(dev, end / PAGE_SIZE - 1, 1); } static bool @@ -718,6 +727,9 @@ int i915_gem_gtt_init(struct drm_device *dev) dev_priv->gtt.do_idle_maps = needs_idle_maps(dev); + dev_priv->gtt.gtt_clear_range = i915_ggtt_clear_range; + dev_priv->gtt.gtt_insert_entries = i915_ggtt_insert_entries; + return 0; } @@ -771,6 +783,9 @@ int i915_gem_gtt_init(struct drm_device *dev) DRM_DEBUG_DRIVER("GMADR size = %ldM\n", dev_priv->gtt.mappable_end >> 20); DRM_DEBUG_DRIVER("GTT stolen size = %dM\n", dev_priv->mm.gtt->stolen_size >> 20); + dev_priv->gtt.gtt_clear_range = gen6_ggtt_clear_range; + dev_priv->gtt.gtt_insert_entries = gen6_ggtt_insert_entries; + return 0; err_out: From def886c3768d24c4e0aa56ff98b5a468c2b5c9bf Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Thu, 24 Jan 2013 14:44:56 -0800 Subject: [PATCH 084/101] drm/i915: vfuncs for ppgtt Like for the global gtt we want a notch more flexibility here. Only big change (besides a few tiny function parameter adjustments) was to move gen6_ppgtt_insert_entries up (and remove _sg_ from its name, we only have one kind of insert_entries since the last gtt cleanup). We could also extract the platform ppgtt setup/teardown code a bit better, but I don't care that much. With this we have the hw details of pte writing nicely hidden away behind a bit of abstraction. Which should pave the way for different/multiple ppgtts (e.g. what we need for real ppgtt support). Reviewed-by: Damien Lespiau Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_drv.h | 10 ++- drivers/gpu/drm/i915/i915_gem_gtt.c | 111 ++++++++++++++-------------- 2 files changed, 65 insertions(+), 56 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index fb0815bebe0f..4be7c68bf5fd 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -412,6 +412,15 @@ struct i915_hw_ppgtt { uint32_t pd_offset; dma_addr_t *pt_dma_addr; dma_addr_t scratch_page_dma_addr; + + /* pte functions, mirroring the interface of the global gtt. */ + void (*clear_range)(struct i915_hw_ppgtt *ppgtt, + unsigned int first_entry, + unsigned int num_entries); + void (*insert_entries)(struct i915_hw_ppgtt *ppgtt, + struct sg_table *st, + unsigned int pg_start, + enum i915_cache_level cache_level); }; @@ -1662,7 +1671,6 @@ int i915_gem_context_destroy_ioctl(struct drm_device *dev, void *data, struct drm_file *file); /* i915_gem_gtt.c */ -int __must_check i915_gem_init_aliasing_ppgtt(struct drm_device *dev); void i915_gem_cleanup_aliasing_ppgtt(struct drm_device *dev); void i915_ppgtt_bind_object(struct i915_hw_ppgtt *ppgtt, struct drm_i915_gem_object *obj, diff --git a/drivers/gpu/drm/i915/i915_gem_gtt.c b/drivers/gpu/drm/i915/i915_gem_gtt.c index 4712626f8dc1..f63dbc7a89ce 100644 --- a/drivers/gpu/drm/i915/i915_gem_gtt.c +++ b/drivers/gpu/drm/i915/i915_gem_gtt.c @@ -77,7 +77,7 @@ static inline gtt_pte_t pte_encode(struct drm_device *dev, } /* PPGTT support for Sandybdrige/Gen6 and later */ -static void i915_ppgtt_clear_range(struct i915_hw_ppgtt *ppgtt, +static void gen6_ppgtt_clear_range(struct i915_hw_ppgtt *ppgtt, unsigned first_entry, unsigned num_entries) { @@ -108,7 +108,51 @@ static void i915_ppgtt_clear_range(struct i915_hw_ppgtt *ppgtt, } } -int i915_gem_init_aliasing_ppgtt(struct drm_device *dev) +static void gen6_ppgtt_insert_entries(struct i915_hw_ppgtt *ppgtt, + struct sg_table *pages, + unsigned first_entry, + enum i915_cache_level cache_level) +{ + gtt_pte_t *pt_vaddr; + unsigned act_pd = first_entry / I915_PPGTT_PT_ENTRIES; + unsigned first_pte = first_entry % I915_PPGTT_PT_ENTRIES; + unsigned i, j, m, segment_len; + dma_addr_t page_addr; + struct scatterlist *sg; + + /* init sg walking */ + sg = pages->sgl; + i = 0; + segment_len = sg_dma_len(sg) >> PAGE_SHIFT; + m = 0; + + while (i < pages->nents) { + pt_vaddr = kmap_atomic(ppgtt->pt_pages[act_pd]); + + for (j = first_pte; j < I915_PPGTT_PT_ENTRIES; j++) { + page_addr = sg_dma_address(sg) + (m << PAGE_SHIFT); + pt_vaddr[j] = pte_encode(ppgtt->dev, page_addr, + cache_level); + + /* grab the next page */ + if (++m == segment_len) { + if (++i == pages->nents) + break; + + sg = sg_next(sg); + segment_len = sg_dma_len(sg) >> PAGE_SHIFT; + m = 0; + } + } + + kunmap_atomic(pt_vaddr); + + first_pte = 0; + act_pd++; + } +} + +static int i915_gem_init_aliasing_ppgtt(struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; struct i915_hw_ppgtt *ppgtt; @@ -127,6 +171,8 @@ int i915_gem_init_aliasing_ppgtt(struct drm_device *dev) ppgtt->dev = dev; ppgtt->num_pd_entries = I915_PPGTT_PD_ENTRIES; + ppgtt->clear_range = gen6_ppgtt_clear_range; + ppgtt->insert_entries = gen6_ppgtt_insert_entries; ppgtt->pt_pages = kzalloc(sizeof(struct page *)*ppgtt->num_pd_entries, GFP_KERNEL); if (!ppgtt->pt_pages) @@ -159,8 +205,8 @@ int i915_gem_init_aliasing_ppgtt(struct drm_device *dev) ppgtt->scratch_page_dma_addr = dev_priv->gtt.scratch_page_dma; - i915_ppgtt_clear_range(ppgtt, 0, - ppgtt->num_pd_entries*I915_PPGTT_PT_ENTRIES); + ppgtt->clear_range(ppgtt, 0, + ppgtt->num_pd_entries*I915_PPGTT_PT_ENTRIES); ppgtt->pd_offset = (first_pd_entry_in_global_pt)*sizeof(gtt_pte_t); @@ -209,66 +255,21 @@ void i915_gem_cleanup_aliasing_ppgtt(struct drm_device *dev) kfree(ppgtt); } -static void i915_ppgtt_insert_sg_entries(struct i915_hw_ppgtt *ppgtt, - const struct sg_table *pages, - unsigned first_entry, - enum i915_cache_level cache_level) -{ - gtt_pte_t *pt_vaddr; - unsigned act_pd = first_entry / I915_PPGTT_PT_ENTRIES; - unsigned first_pte = first_entry % I915_PPGTT_PT_ENTRIES; - unsigned i, j, m, segment_len; - dma_addr_t page_addr; - struct scatterlist *sg; - - /* init sg walking */ - sg = pages->sgl; - i = 0; - segment_len = sg_dma_len(sg) >> PAGE_SHIFT; - m = 0; - - while (i < pages->nents) { - pt_vaddr = kmap_atomic(ppgtt->pt_pages[act_pd]); - - for (j = first_pte; j < I915_PPGTT_PT_ENTRIES; j++) { - page_addr = sg_dma_address(sg) + (m << PAGE_SHIFT); - pt_vaddr[j] = pte_encode(ppgtt->dev, page_addr, - cache_level); - - /* grab the next page */ - if (++m == segment_len) { - if (++i == pages->nents) - break; - - sg = sg_next(sg); - segment_len = sg_dma_len(sg) >> PAGE_SHIFT; - m = 0; - } - } - - kunmap_atomic(pt_vaddr); - - first_pte = 0; - act_pd++; - } -} - void i915_ppgtt_bind_object(struct i915_hw_ppgtt *ppgtt, struct drm_i915_gem_object *obj, enum i915_cache_level cache_level) { - i915_ppgtt_insert_sg_entries(ppgtt, - obj->pages, - obj->gtt_space->start >> PAGE_SHIFT, - cache_level); + ppgtt->insert_entries(ppgtt, obj->pages, + obj->gtt_space->start >> PAGE_SHIFT, + cache_level); } void i915_ppgtt_unbind_object(struct i915_hw_ppgtt *ppgtt, struct drm_i915_gem_object *obj) { - i915_ppgtt_clear_range(ppgtt, - obj->gtt_space->start >> PAGE_SHIFT, - obj->base.size >> PAGE_SHIFT); + ppgtt->clear_range(ppgtt, + obj->gtt_space->start >> PAGE_SHIFT, + obj->base.size >> PAGE_SHIFT); } void i915_gem_init_ppgtt(struct drm_device *dev) From 960e3e429f0c7d9e27e60cf8fa2f51ada71e717e Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Thu, 24 Jan 2013 14:44:57 -0800 Subject: [PATCH 085/101] drm/i915: pte_encode is gen6+ All the other gen6+ hw code has the gen6_ prefix, so be consistent about it. Reviewed-by: Damien Lespiau Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_gem_gtt.c | 24 ++++++++++++++---------- 1 file changed, 14 insertions(+), 10 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_gem_gtt.c b/drivers/gpu/drm/i915/i915_gem_gtt.c index f63dbc7a89ce..d17198210568 100644 --- a/drivers/gpu/drm/i915/i915_gem_gtt.c +++ b/drivers/gpu/drm/i915/i915_gem_gtt.c @@ -44,9 +44,9 @@ typedef uint32_t gtt_pte_t; #define GEN6_PTE_CACHE_LLC_MLC (3 << 1) #define GEN6_PTE_ADDR_ENCODE(addr) GEN6_GTT_ADDR_ENCODE(addr) -static inline gtt_pte_t pte_encode(struct drm_device *dev, - dma_addr_t addr, - enum i915_cache_level level) +static inline gtt_pte_t gen6_pte_encode(struct drm_device *dev, + dma_addr_t addr, + enum i915_cache_level level) { gtt_pte_t pte = GEN6_PTE_VALID; pte |= GEN6_PTE_ADDR_ENCODE(addr); @@ -87,8 +87,9 @@ static void gen6_ppgtt_clear_range(struct i915_hw_ppgtt *ppgtt, unsigned first_pte = first_entry % I915_PPGTT_PT_ENTRIES; unsigned last_pte, i; - scratch_pte = pte_encode(ppgtt->dev, ppgtt->scratch_page_dma_addr, - I915_CACHE_LLC); + scratch_pte = gen6_pte_encode(ppgtt->dev, + ppgtt->scratch_page_dma_addr, + I915_CACHE_LLC); while (num_entries) { last_pte = first_pte + num_entries; @@ -131,8 +132,8 @@ static void gen6_ppgtt_insert_entries(struct i915_hw_ppgtt *ppgtt, for (j = first_pte; j < I915_PPGTT_PT_ENTRIES; j++) { page_addr = sg_dma_address(sg) + (m << PAGE_SHIFT); - pt_vaddr[j] = pte_encode(ppgtt->dev, page_addr, - cache_level); + pt_vaddr[j] = gen6_pte_encode(ppgtt->dev, page_addr, + cache_level); /* grab the next page */ if (++m == segment_len) { @@ -421,7 +422,8 @@ static void gen6_ggtt_insert_entries(struct drm_device *dev, len = sg_dma_len(sg) >> PAGE_SHIFT; for (m = 0; m < len; m++) { addr = sg_dma_address(sg) + (m << PAGE_SHIFT); - iowrite32(pte_encode(dev, addr, level), >t_entries[i]); + iowrite32(gen6_pte_encode(dev, addr, level), + >t_entries[i]); i++; } } @@ -433,7 +435,8 @@ static void gen6_ggtt_insert_entries(struct drm_device *dev, * hardware should work, we must keep this posting read for paranoia. */ if (i != 0) - WARN_ON(readl(>t_entries[i-1]) != pte_encode(dev, addr, level)); + WARN_ON(readl(>t_entries[i-1]) + != gen6_pte_encode(dev, addr, level)); /* This next bit makes the above posting read even more important. We * want to flush the TLBs only after we're certain all the PTE updates @@ -458,7 +461,8 @@ static void gen6_ggtt_clear_range(struct drm_device *dev, first_entry, num_entries, max_entries)) num_entries = max_entries; - scratch_pte = pte_encode(dev, dev_priv->gtt.scratch_page_dma, I915_CACHE_LLC); + scratch_pte = gen6_pte_encode(dev, dev_priv->gtt.scratch_page_dma, + I915_CACHE_LLC); for (i = 0; i < num_entries; i++) iowrite32(scratch_pte, >t_base[i]); readl(gtt_base); From 3440d265857b411a13ed8f67814a29fa2011cdb3 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Thu, 24 Jan 2013 13:49:56 -0800 Subject: [PATCH 086/101] drm/i915: extract hw ppgtt setup/cleanup code At the moment only cosmetics, but being able to initialize/cleanup arbitrary ppgtt address spaces paves the way to have more than one of them ... Just in case we ever get around to implementing real per-process address spaces. Note that in that case another vfunc for ppgtt would be beneficial though. But that can wait until the code grows a second place which initializes ppgtts. Reviewed-by: Damien Lespiau Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_drv.h | 1 + drivers/gpu/drm/i915/i915_gem_gtt.c | 68 +++++++++++++++++++---------- 2 files changed, 45 insertions(+), 24 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 4be7c68bf5fd..cfae2cee3e1c 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -421,6 +421,7 @@ struct i915_hw_ppgtt { struct sg_table *st, unsigned int pg_start, enum i915_cache_level cache_level); + void (*cleanup)(struct i915_hw_ppgtt *ppgtt); }; diff --git a/drivers/gpu/drm/i915/i915_gem_gtt.c b/drivers/gpu/drm/i915/i915_gem_gtt.c index d17198210568..55020676474c 100644 --- a/drivers/gpu/drm/i915/i915_gem_gtt.c +++ b/drivers/gpu/drm/i915/i915_gem_gtt.c @@ -153,10 +153,28 @@ static void gen6_ppgtt_insert_entries(struct i915_hw_ppgtt *ppgtt, } } -static int i915_gem_init_aliasing_ppgtt(struct drm_device *dev) +static void gen6_ppgtt_cleanup(struct i915_hw_ppgtt *ppgtt) { + int i; + + if (ppgtt->pt_dma_addr) { + for (i = 0; i < ppgtt->num_pd_entries; i++) + pci_unmap_page(ppgtt->dev->pdev, + ppgtt->pt_dma_addr[i], + 4096, PCI_DMA_BIDIRECTIONAL); + } + + kfree(ppgtt->pt_dma_addr); + for (i = 0; i < ppgtt->num_pd_entries; i++) + __free_page(ppgtt->pt_pages[i]); + kfree(ppgtt->pt_pages); + kfree(ppgtt); +} + +static int gen6_ppgtt_init(struct i915_hw_ppgtt *ppgtt) +{ + struct drm_device *dev = ppgtt->dev; struct drm_i915_private *dev_priv = dev->dev_private; - struct i915_hw_ppgtt *ppgtt; unsigned first_pd_entry_in_global_pt; int i; int ret = -ENOMEM; @@ -166,18 +184,14 @@ static int i915_gem_init_aliasing_ppgtt(struct drm_device *dev) * now. */ first_pd_entry_in_global_pt = dev_priv->mm.gtt->gtt_total_entries - I915_PPGTT_PD_ENTRIES; - ppgtt = kzalloc(sizeof(*ppgtt), GFP_KERNEL); - if (!ppgtt) - return ret; - - ppgtt->dev = dev; ppgtt->num_pd_entries = I915_PPGTT_PD_ENTRIES; ppgtt->clear_range = gen6_ppgtt_clear_range; ppgtt->insert_entries = gen6_ppgtt_insert_entries; + ppgtt->cleanup = gen6_ppgtt_cleanup; ppgtt->pt_pages = kzalloc(sizeof(struct page *)*ppgtt->num_pd_entries, GFP_KERNEL); if (!ppgtt->pt_pages) - goto err_ppgtt; + return -ENOMEM; for (i = 0; i < ppgtt->num_pd_entries; i++) { ppgtt->pt_pages[i] = alloc_page(GFP_KERNEL); @@ -211,8 +225,6 @@ static int i915_gem_init_aliasing_ppgtt(struct drm_device *dev) ppgtt->pd_offset = (first_pd_entry_in_global_pt)*sizeof(gtt_pte_t); - dev_priv->mm.aliasing_ppgtt = ppgtt; - return 0; err_pd_pin: @@ -228,8 +240,27 @@ err_pt_alloc: __free_page(ppgtt->pt_pages[i]); } kfree(ppgtt->pt_pages); -err_ppgtt: - kfree(ppgtt); + + return ret; +} + +static int i915_gem_init_aliasing_ppgtt(struct drm_device *dev) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + struct i915_hw_ppgtt *ppgtt; + int ret; + + ppgtt = kzalloc(sizeof(*ppgtt), GFP_KERNEL); + if (!ppgtt) + return -ENOMEM; + + ppgtt->dev = dev; + + ret = gen6_ppgtt_init(ppgtt); + if (ret) + kfree(ppgtt); + else + dev_priv->mm.aliasing_ppgtt = ppgtt; return ret; } @@ -238,22 +269,11 @@ void i915_gem_cleanup_aliasing_ppgtt(struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; struct i915_hw_ppgtt *ppgtt = dev_priv->mm.aliasing_ppgtt; - int i; if (!ppgtt) return; - if (ppgtt->pt_dma_addr) { - for (i = 0; i < ppgtt->num_pd_entries; i++) - pci_unmap_page(dev->pdev, ppgtt->pt_dma_addr[i], - 4096, PCI_DMA_BIDIRECTIONAL); - } - - kfree(ppgtt->pt_dma_addr); - for (i = 0; i < ppgtt->num_pd_entries; i++) - __free_page(ppgtt->pt_pages[i]); - kfree(ppgtt->pt_pages); - kfree(ppgtt); + ppgtt->cleanup(ppgtt); } void i915_ppgtt_bind_object(struct i915_hw_ppgtt *ppgtt, From baa09f5fd8a6d033ec075355dda99a65b7f6a0f3 Mon Sep 17 00:00:00 2001 From: Ben Widawsky Date: Thu, 24 Jan 2013 13:49:57 -0800 Subject: [PATCH 087/101] drm/i915: Add probe and remove to the gtt ops The idea, and much of the code came originally from: commit 0712f0249c3148d8cf42a3703403c278590d4de5 Author: Ben Widawsky Date: Fri Jan 18 17:23:16 2013 -0800 drm/i915: Create a vtable for i915 gtt Daniel didn't like the color of that patch series, and so I asked him to start something which appealed to his sense of color. The preceding patches are those, and now this is going on top of that. [extracted from the original commit message] One immediately obvious thing to implement is our gmch probing. The init function was getting massively bloated. Fundamentally, all that's needed from GMCH probing is the GTT size, and the stolen size. It makes design sense to put the mappable calculation in there as well, but the code turns out a bit nicer without it (IMO) The intel_gtt bridge thing is still here, but the subsequent patches will finish ripping that out. Signed-off-by: Ben Widawsky [danvet: Bikeshedded one comment (GMADR is just the PCI aperture, we use it for other things than just accessing tiled surfaces through a linear view) and cut the newly added long lines a bit. Also one checkpatch error.] Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_dma.c | 2 +- drivers/gpu/drm/i915/i915_drv.h | 5 +- drivers/gpu/drm/i915/i915_gem_gtt.c | 194 ++++++++++++++++------------ 3 files changed, 118 insertions(+), 83 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_dma.c b/drivers/gpu/drm/i915/i915_dma.c index 11c7aa80e29b..cf0610330135 100644 --- a/drivers/gpu/drm/i915/i915_dma.c +++ b/drivers/gpu/drm/i915/i915_dma.c @@ -1665,7 +1665,7 @@ out_mtrrfree: out_rmmap: pci_iounmap(dev->pdev, dev_priv->regs); put_gmch: - i915_gem_gtt_fini(dev); + dev_priv->gtt.gtt_remove(dev); put_bridge: pci_dev_put(dev_priv->bridge_dev); free_priv: diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index cfae2cee3e1c..dee8d5c7a235 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -381,6 +381,7 @@ enum i915_cache_level { struct i915_gtt { unsigned long start; /* Start offset of used GTT */ size_t total; /* Total size GTT can map */ + size_t stolen_size; /* Total size of stolen memory */ unsigned long mappable_end; /* End offset that we can CPU map */ struct io_mapping *mappable; /* Mapping to our CPU mappable region */ @@ -394,6 +395,9 @@ struct i915_gtt { struct page *scratch_page; /* global gtt ops */ + int (*gtt_probe)(struct drm_device *dev, size_t *gtt_total, + size_t *stolen); + void (*gtt_remove)(struct drm_device *dev); void (*gtt_clear_range)(struct drm_device *dev, unsigned int first_entry, unsigned int num_entries); @@ -1689,7 +1693,6 @@ void i915_gem_init_global_gtt(struct drm_device *dev); void i915_gem_setup_global_gtt(struct drm_device *dev, unsigned long start, unsigned long mappable_end, unsigned long end); int i915_gem_gtt_init(struct drm_device *dev); -void i915_gem_gtt_fini(struct drm_device *dev); static inline void i915_gem_chipset_flush(struct drm_device *dev) { if (INTEL_INFO(dev)->gen < 6) diff --git a/drivers/gpu/drm/i915/i915_gem_gtt.c b/drivers/gpu/drm/i915/i915_gem_gtt.c index 55020676474c..87249e8cd4a0 100644 --- a/drivers/gpu/drm/i915/i915_gem_gtt.c +++ b/drivers/gpu/drm/i915/i915_gem_gtt.c @@ -707,14 +707,14 @@ static inline unsigned int gen6_get_total_gtt_size(u16 snb_gmch_ctl) return snb_gmch_ctl << 20; } -static inline unsigned int gen6_get_stolen_size(u16 snb_gmch_ctl) +static inline size_t gen6_get_stolen_size(u16 snb_gmch_ctl) { snb_gmch_ctl >>= SNB_GMCH_GMS_SHIFT; snb_gmch_ctl &= SNB_GMCH_GMS_MASK; return snb_gmch_ctl << 25; /* 32 MB units */ } -static inline unsigned int gen7_get_stolen_size(u16 snb_gmch_ctl) +static inline size_t gen7_get_stolen_size(u16 snb_gmch_ctl) { static const int stolen_decoder[] = { 0, 0, 0, 0, 0, 32, 48, 64, 128, 256, 96, 160, 224, 352}; @@ -723,109 +723,141 @@ static inline unsigned int gen7_get_stolen_size(u16 snb_gmch_ctl) return stolen_decoder[snb_gmch_ctl] << 20; } -int i915_gem_gtt_init(struct drm_device *dev) +static int gen6_gmch_probe(struct drm_device *dev, + size_t *gtt_total, + size_t *stolen) { struct drm_i915_private *dev_priv = dev->dev_private; phys_addr_t gtt_bus_addr; + unsigned int gtt_size; u16 snb_gmch_ctl; int ret; - dev_priv->gtt.mappable_base = pci_resource_start(dev->pdev, 2); - dev_priv->gtt.mappable_end = pci_resource_len(dev->pdev, 2); - - /* On modern platforms we need not worry ourself with the legacy - * hostbridge query stuff. Skip it entirely + /* 64/512MB is the current min/max we actually know of, but this is just + * a coarse sanity check. */ - if (INTEL_INFO(dev)->gen < 6) { - ret = intel_gmch_probe(dev_priv->bridge_dev, dev->pdev, NULL); - if (!ret) { - DRM_ERROR("failed to set up gmch\n"); - return -EIO; - } - - dev_priv->mm.gtt = intel_gtt_get(); - if (!dev_priv->mm.gtt) { - DRM_ERROR("Failed to initialize GTT\n"); - intel_gmch_remove(); - return -ENODEV; - } - - dev_priv->gtt.do_idle_maps = needs_idle_maps(dev); - - dev_priv->gtt.gtt_clear_range = i915_ggtt_clear_range; - dev_priv->gtt.gtt_insert_entries = i915_ggtt_insert_entries; - - return 0; + if ((dev_priv->gtt.mappable_end < (64<<20) || + (dev_priv->gtt.mappable_end > (512<<20)))) { + DRM_ERROR("Unknown GMADR size (%lx)\n", + dev_priv->gtt.mappable_end); + return -ENXIO; } if (!pci_set_dma_mask(dev->pdev, DMA_BIT_MASK(40))) pci_set_consistent_dma_mask(dev->pdev, DMA_BIT_MASK(40)); + pci_read_config_word(dev->pdev, SNB_GMCH_CTRL, &snb_gmch_ctl); + gtt_size = gen6_get_total_gtt_size(snb_gmch_ctl); + + if (IS_GEN7(dev)) + *stolen = gen7_get_stolen_size(snb_gmch_ctl); + else + *stolen = gen6_get_stolen_size(snb_gmch_ctl); + + *gtt_total = (gtt_size / sizeof(gtt_pte_t)) << PAGE_SHIFT; + + /* For GEN6+ the PTEs for the ggtt live at 2MB + BAR0 */ + gtt_bus_addr = pci_resource_start(dev->pdev, 0) + (2<<20); + dev_priv->gtt.gsm = ioremap_wc(gtt_bus_addr, gtt_size); + if (!dev_priv->gtt.gsm) { + DRM_ERROR("Failed to map the gtt page table\n"); + return -ENOMEM; + } + + ret = setup_scratch_page(dev); + if (ret) + DRM_ERROR("Scratch setup failed\n"); + + dev_priv->gtt.gtt_clear_range = gen6_ggtt_clear_range; + dev_priv->gtt.gtt_insert_entries = gen6_ggtt_insert_entries; + + return ret; +} + +void gen6_gmch_remove(struct drm_device *dev) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + iounmap(dev_priv->gtt.gsm); + teardown_scratch_page(dev_priv->dev); + kfree(dev_priv->mm.gtt); +} + +static int i915_gmch_probe(struct drm_device *dev, + size_t *gtt_total, + size_t *stolen) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + int ret; + + /* This is a temporary hack to make the code cleaner in + * i915_gem_gtt_init. I promise it will go away very shortly. */ + kfree(dev_priv->mm.gtt); + + ret = intel_gmch_probe(dev_priv->bridge_dev, dev_priv->dev->pdev, NULL); + if (!ret) { + DRM_ERROR("failed to set up gmch\n"); + return -EIO; + } + + dev_priv->mm.gtt = intel_gtt_get(); + if (!dev_priv->mm.gtt) { + DRM_ERROR("Failed to initialize GTT\n"); + intel_gmch_remove(); + return -ENODEV; + } + + dev_priv->gtt.do_idle_maps = needs_idle_maps(dev_priv->dev); + dev_priv->gtt.gtt_clear_range = i915_ggtt_clear_range; + dev_priv->gtt.gtt_insert_entries = i915_ggtt_insert_entries; + + return 0; +} + +static void i915_gmch_remove(struct drm_device *dev) +{ + intel_gmch_remove(); +} + +int i915_gem_gtt_init(struct drm_device *dev) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + struct i915_gtt *gtt = &dev_priv->gtt; + unsigned long gtt_size; + int ret; dev_priv->mm.gtt = kzalloc(sizeof(*dev_priv->mm.gtt), GFP_KERNEL); if (!dev_priv->mm.gtt) return -ENOMEM; - /* For GEN6+ the PTEs for the ggtt live at 2MB + BAR0 */ - gtt_bus_addr = pci_resource_start(dev->pdev, 0) + (2<<20); + gtt->mappable_base = pci_resource_start(dev->pdev, 2); + gtt->mappable_end = pci_resource_len(dev->pdev, 2); - /* i9xx_setup */ - pci_read_config_word(dev->pdev, SNB_GMCH_CTRL, &snb_gmch_ctl); - dev_priv->mm.gtt->gtt_total_entries = - gen6_get_total_gtt_size(snb_gmch_ctl) / sizeof(gtt_pte_t); - if (INTEL_INFO(dev)->gen < 7) - dev_priv->mm.gtt->stolen_size = gen6_get_stolen_size(snb_gmch_ctl); - else - dev_priv->mm.gtt->stolen_size = gen7_get_stolen_size(snb_gmch_ctl); - - /* 64/512MB is the current min/max we actually know of, but this is just a - * coarse sanity check. - */ - if ((dev_priv->gtt.mappable_end < (64<<20) || - (dev_priv->gtt.mappable_end > (512<<20)))) { - DRM_ERROR("Unknown GMADR size (%lx)\n", - dev_priv->gtt.mappable_end); - ret = -ENXIO; - goto err_out; + if (INTEL_INFO(dev)->gen <= 5) { + dev_priv->gtt.gtt_probe = i915_gmch_probe; + dev_priv->gtt.gtt_remove = i915_gmch_remove; + } else { + dev_priv->gtt.gtt_probe = gen6_gmch_probe; + dev_priv->gtt.gtt_remove = gen6_gmch_remove; } - ret = setup_scratch_page(dev); + ret = dev_priv->gtt.gtt_probe(dev, &dev_priv->gtt.total, + &dev_priv->gtt.stolen_size); if (ret) { - DRM_ERROR("Scratch setup failed\n"); - goto err_out; + kfree(dev_priv->mm.gtt); + return ret; } - dev_priv->gtt.gsm = ioremap_wc(gtt_bus_addr, - dev_priv->mm.gtt->gtt_total_entries * sizeof(gtt_pte_t)); - if (!dev_priv->gtt.gsm) { - DRM_ERROR("Failed to map the gtt page table\n"); - teardown_scratch_page(dev); - ret = -ENOMEM; - goto err_out; - } + dev_priv->mm.gtt->gtt_total_entries = dev_priv->gtt.total >> PAGE_SHIFT; + dev_priv->mm.gtt->stolen_size = dev_priv->gtt.stolen_size; - /* GMADR is the PCI aperture used by SW to access tiled GFX surfaces in a linear fashion. */ - DRM_INFO("Memory usable by graphics device = %dM\n", dev_priv->mm.gtt->gtt_total_entries >> 8); - DRM_DEBUG_DRIVER("GMADR size = %ldM\n", dev_priv->gtt.mappable_end >> 20); - DRM_DEBUG_DRIVER("GTT stolen size = %dM\n", dev_priv->mm.gtt->stolen_size >> 20); + gtt_size = (dev_priv->gtt.total >> PAGE_SHIFT) * sizeof(gtt_pte_t); - dev_priv->gtt.gtt_clear_range = gen6_ggtt_clear_range; - dev_priv->gtt.gtt_insert_entries = gen6_ggtt_insert_entries; + /* GMADR is the PCI mmio aperture into the global GTT. */ + DRM_INFO("Memory usable by graphics device = %zdM\n", + dev_priv->gtt.total >> 20); + DRM_DEBUG_DRIVER("GMADR size = %ldM\n", + dev_priv->gtt.mappable_end >> 20); + DRM_DEBUG_DRIVER("GTT stolen size = %zdM\n", + dev_priv->gtt.stolen_size >> 20); return 0; - -err_out: - kfree(dev_priv->mm.gtt); - if (INTEL_INFO(dev)->gen < 6) - intel_gmch_remove(); - return ret; -} - -void i915_gem_gtt_fini(struct drm_device *dev) -{ - struct drm_i915_private *dev_priv = dev->dev_private; - iounmap(dev_priv->gtt.gsm); - teardown_scratch_page(dev); - if (INTEL_INFO(dev)->gen < 6) - intel_gmch_remove(); - kfree(dev_priv->mm.gtt); } From a54c0c279f3864171fe53c66e769d5a137c5c651 Mon Sep 17 00:00:00 2001 From: Ben Widawsky Date: Thu, 24 Jan 2013 14:45:00 -0800 Subject: [PATCH 088/101] drm/i915: remove intel_gtt structure With the probe call in our dispatch table, we can now cut away the last three remaining members in the intel_gtt shared struct and so remove it completely. v2: Rebased on top of Daniel's series Signed-off-by: Ben Widawsky Reviewed-by: Damien Lespiau [danvet: bikeshed commit message a bit.] Signed-off-by: Daniel Vetter --- drivers/char/agp/intel-gtt.c | 36 +++++++++++++++----------- drivers/gpu/drm/i915/i915_drv.h | 3 +-- drivers/gpu/drm/i915/i915_gem_gtt.c | 30 +++++---------------- drivers/gpu/drm/i915/i915_gem_stolen.c | 8 +++--- include/drm/intel-gtt.h | 10 +------ 5 files changed, 33 insertions(+), 54 deletions(-) diff --git a/drivers/char/agp/intel-gtt.c b/drivers/char/agp/intel-gtt.c index ff5f3483e8ea..d8e7e6c9114e 100644 --- a/drivers/char/agp/intel-gtt.c +++ b/drivers/char/agp/intel-gtt.c @@ -60,7 +60,6 @@ struct intel_gtt_driver { }; static struct _intel_private { - struct intel_gtt base; const struct intel_gtt_driver *driver; struct pci_dev *pcidev; /* device one */ struct pci_dev *bridge_dev; @@ -80,6 +79,13 @@ static struct _intel_private { /* Whether i915 needs to use the dmar apis or not. */ unsigned int needs_dmar : 1; phys_addr_t gma_bus_addr; + /* Size of memory reserved for graphics by the BIOS */ + unsigned int stolen_size; + /* Total number of gtt entries. */ + unsigned int gtt_total_entries; + /* Part of the gtt that is mappable by the cpu, for those chips where + * this is not the full gtt. */ + unsigned int gtt_mappable_entries; } intel_private; #define INTEL_GTT_GEN intel_private.driver->gen @@ -510,7 +516,7 @@ static unsigned int intel_gtt_total_entries(void) /* On previous hardware, the GTT size was just what was * required to map the aperture. */ - return intel_private.base.gtt_mappable_entries; + return intel_private.gtt_mappable_entries; } } @@ -576,8 +582,8 @@ static int intel_gtt_init(void) if (ret != 0) return ret; - intel_private.base.gtt_mappable_entries = intel_gtt_mappable_entries(); - intel_private.base.gtt_total_entries = intel_gtt_total_entries(); + intel_private.gtt_mappable_entries = intel_gtt_mappable_entries(); + intel_private.gtt_total_entries = intel_gtt_total_entries(); /* save the PGETBL reg for resume */ intel_private.PGETBL_save = @@ -589,10 +595,10 @@ static int intel_gtt_init(void) dev_info(&intel_private.bridge_dev->dev, "detected gtt size: %dK total, %dK mappable\n", - intel_private.base.gtt_total_entries * 4, - intel_private.base.gtt_mappable_entries * 4); + intel_private.gtt_total_entries * 4, + intel_private.gtt_mappable_entries * 4); - gtt_map_size = intel_private.base.gtt_total_entries * 4; + gtt_map_size = intel_private.gtt_total_entries * 4; intel_private.gtt = NULL; if (INTEL_GTT_GEN < 6 && INTEL_GTT_GEN > 2) @@ -609,7 +615,7 @@ static int intel_gtt_init(void) global_cache_flush(); /* FIXME: ? */ - intel_private.base.stolen_size = intel_gtt_stolen_size(); + intel_private.stolen_size = intel_gtt_stolen_size(); intel_private.needs_dmar = USE_PCI_DMA_API && INTEL_GTT_GEN > 2; @@ -637,8 +643,7 @@ static int intel_fake_agp_fetch_size(void) unsigned int aper_size; int i; - aper_size = (intel_private.base.gtt_mappable_entries << PAGE_SHIFT) - / MB(1); + aper_size = (intel_private.gtt_mappable_entries << PAGE_SHIFT) / MB(1); for (i = 0; i < num_sizes; i++) { if (aper_size == intel_fake_agp_sizes[i].size) { @@ -845,8 +850,8 @@ static int intel_fake_agp_insert_entries(struct agp_memory *mem, int ret = -EINVAL; if (intel_private.clear_fake_agp) { - int start = intel_private.base.stolen_size / PAGE_SIZE; - int end = intel_private.base.gtt_mappable_entries; + int start = intel_private.stolen_size / PAGE_SIZE; + int end = intel_private.gtt_mappable_entries; intel_gtt_clear_range(start, end - start); intel_private.clear_fake_agp = false; } @@ -857,7 +862,7 @@ static int intel_fake_agp_insert_entries(struct agp_memory *mem, if (mem->page_count == 0) goto out; - if (pg_start + mem->page_count > intel_private.base.gtt_total_entries) + if (pg_start + mem->page_count > intel_private.gtt_total_entries) goto out_err; if (type != mem->type) @@ -1366,9 +1371,10 @@ int intel_gmch_probe(struct pci_dev *bridge_pdev, struct pci_dev *gpu_pdev, } EXPORT_SYMBOL(intel_gmch_probe); -struct intel_gtt *intel_gtt_get(void) +void intel_gtt_get(size_t *gtt_total, size_t *stolen_size) { - return &intel_private.base; + *gtt_total = intel_private.gtt_total_entries << PAGE_SHIFT; + *stolen_size = intel_private.stolen_size; } EXPORT_SYMBOL(intel_gtt_get); diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index dee8d5c7a235..d3274164143d 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -406,6 +406,7 @@ struct i915_gtt { unsigned int pg_start, enum i915_cache_level cache_level); }; +#define gtt_total_entries(gtt) ((gtt).total >> PAGE_SHIFT) #define I915_PPGTT_PD_ENTRIES 512 #define I915_PPGTT_PT_ENTRIES 1024 @@ -696,8 +697,6 @@ struct intel_l3_parity { }; struct i915_gem_mm { - /** Bridge to intel-gtt-ko */ - struct intel_gtt *gtt; /** Memory allocator for GTT stolen memory */ struct drm_mm stolen; /** Memory allocator for GTT */ diff --git a/drivers/gpu/drm/i915/i915_gem_gtt.c b/drivers/gpu/drm/i915/i915_gem_gtt.c index 87249e8cd4a0..f7e0018626bd 100644 --- a/drivers/gpu/drm/i915/i915_gem_gtt.c +++ b/drivers/gpu/drm/i915/i915_gem_gtt.c @@ -182,7 +182,8 @@ static int gen6_ppgtt_init(struct i915_hw_ppgtt *ppgtt) /* ppgtt PDEs reside in the global gtt pagetable, which has 512*1024 * entries. For aliasing ppgtt support we just steal them at the end for * now. */ - first_pd_entry_in_global_pt = dev_priv->mm.gtt->gtt_total_entries - I915_PPGTT_PD_ENTRIES; + first_pd_entry_in_global_pt = + gtt_total_entries(dev_priv->gtt) - I915_PPGTT_PD_ENTRIES; ppgtt->num_pd_entries = I915_PPGTT_PD_ENTRIES; ppgtt->clear_range = gen6_ppgtt_clear_range; @@ -473,7 +474,7 @@ static void gen6_ggtt_clear_range(struct drm_device *dev, struct drm_i915_private *dev_priv = dev->dev_private; gtt_pte_t scratch_pte; gtt_pte_t __iomem *gtt_base = (gtt_pte_t __iomem *) dev_priv->gtt.gsm + first_entry; - const int max_entries = dev_priv->mm.gtt->gtt_total_entries - first_entry; + const int max_entries = gtt_total_entries(dev_priv->gtt) - first_entry; int i; if (WARN(num_entries > max_entries, @@ -634,7 +635,7 @@ void i915_gem_init_global_gtt(struct drm_device *dev) unsigned long gtt_size, mappable_size; int ret; - gtt_size = dev_priv->mm.gtt->gtt_total_entries << PAGE_SHIFT; + gtt_size = dev_priv->gtt.total; mappable_size = dev_priv->gtt.mappable_end; if (intel_enable_ppgtt(dev) && HAS_ALIASING_PPGTT(dev)) { @@ -778,7 +779,6 @@ void gen6_gmch_remove(struct drm_device *dev) struct drm_i915_private *dev_priv = dev->dev_private; iounmap(dev_priv->gtt.gsm); teardown_scratch_page(dev_priv->dev); - kfree(dev_priv->mm.gtt); } static int i915_gmch_probe(struct drm_device *dev, @@ -788,22 +788,13 @@ static int i915_gmch_probe(struct drm_device *dev, struct drm_i915_private *dev_priv = dev->dev_private; int ret; - /* This is a temporary hack to make the code cleaner in - * i915_gem_gtt_init. I promise it will go away very shortly. */ - kfree(dev_priv->mm.gtt); - ret = intel_gmch_probe(dev_priv->bridge_dev, dev_priv->dev->pdev, NULL); if (!ret) { DRM_ERROR("failed to set up gmch\n"); return -EIO; } - dev_priv->mm.gtt = intel_gtt_get(); - if (!dev_priv->mm.gtt) { - DRM_ERROR("Failed to initialize GTT\n"); - intel_gmch_remove(); - return -ENODEV; - } + intel_gtt_get(gtt_total, stolen); dev_priv->gtt.do_idle_maps = needs_idle_maps(dev_priv->dev); dev_priv->gtt.gtt_clear_range = i915_ggtt_clear_range; @@ -824,10 +815,6 @@ int i915_gem_gtt_init(struct drm_device *dev) unsigned long gtt_size; int ret; - dev_priv->mm.gtt = kzalloc(sizeof(*dev_priv->mm.gtt), GFP_KERNEL); - if (!dev_priv->mm.gtt) - return -ENOMEM; - gtt->mappable_base = pci_resource_start(dev->pdev, 2); gtt->mappable_end = pci_resource_len(dev->pdev, 2); @@ -841,13 +828,8 @@ int i915_gem_gtt_init(struct drm_device *dev) ret = dev_priv->gtt.gtt_probe(dev, &dev_priv->gtt.total, &dev_priv->gtt.stolen_size); - if (ret) { - kfree(dev_priv->mm.gtt); + if (ret) return ret; - } - - dev_priv->mm.gtt->gtt_total_entries = dev_priv->gtt.total >> PAGE_SHIFT; - dev_priv->mm.gtt->stolen_size = dev_priv->gtt.stolen_size; gtt_size = (dev_priv->gtt.total >> PAGE_SHIFT) * sizeof(gtt_pte_t); diff --git a/drivers/gpu/drm/i915/i915_gem_stolen.c b/drivers/gpu/drm/i915/i915_gem_stolen.c index f21ae17e298f..69d97cbac13c 100644 --- a/drivers/gpu/drm/i915/i915_gem_stolen.c +++ b/drivers/gpu/drm/i915/i915_gem_stolen.c @@ -187,11 +187,11 @@ int i915_gem_init_stolen(struct drm_device *dev) if (dev_priv->mm.stolen_base == 0) return 0; - DRM_DEBUG_KMS("found %d bytes of stolen memory at %08lx\n", - dev_priv->mm.gtt->stolen_size, dev_priv->mm.stolen_base); + DRM_DEBUG_KMS("found %zd bytes of stolen memory at %08lx\n", + dev_priv->gtt.stolen_size, dev_priv->mm.stolen_base); /* Basic memrange allocator for stolen space */ - drm_mm_init(&dev_priv->mm.stolen, 0, dev_priv->mm.gtt->stolen_size); + drm_mm_init(&dev_priv->mm.stolen, 0, dev_priv->gtt.stolen_size); return 0; } @@ -205,7 +205,7 @@ i915_pages_create_for_stolen(struct drm_device *dev, struct scatterlist *sg; DRM_DEBUG_DRIVER("offset=0x%x, size=%d\n", offset, size); - BUG_ON(offset > dev_priv->mm.gtt->stolen_size - size); + BUG_ON(offset > dev_priv->gtt.stolen_size - size); /* We hide that we have no struct page backing our stolen object * by wrapping the contiguous physical allocation with a fake diff --git a/include/drm/intel-gtt.h b/include/drm/intel-gtt.h index 769b6c79097e..cf105557fea9 100644 --- a/include/drm/intel-gtt.h +++ b/include/drm/intel-gtt.h @@ -3,15 +3,7 @@ #ifndef _DRM_INTEL_GTT_H #define _DRM_INTEL_GTT_H -struct intel_gtt { - /* Size of memory reserved for graphics by the BIOS */ - unsigned int stolen_size; - /* Total number of gtt entries. */ - unsigned int gtt_total_entries; - /* Part of the gtt that is mappable by the cpu, for those chips where - * this is not the full gtt. */ - unsigned int gtt_mappable_entries; -} *intel_gtt_get(void); +void intel_gtt_get(size_t *gtt_total, size_t *stolen_size); int intel_gmch_probe(struct pci_dev *bridge_pdev, struct pci_dev *gpu_pdev, struct agp_bridge_data *bridge); From e78891ca7648a14dda5760be7b03eba7c628a804 Mon Sep 17 00:00:00 2001 From: Ben Widawsky Date: Fri, 25 Jan 2013 16:41:04 -0800 Subject: [PATCH 089/101] drm/i915: Reclaim GTT space for failed PPGTT When the PPGTT init fails, we may as well reuse the space that we were reserving for the PPGTT PDEs. This also fixes an extraneous mutex_unlock. Reviewed-by: Chris Wilson Signed-off-by: Ben Widawsky Reviewed-by: Jani Nikula Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_gem_gtt.c | 33 ++++++++++++++--------------- 1 file changed, 16 insertions(+), 17 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_gem_gtt.c b/drivers/gpu/drm/i915/i915_gem_gtt.c index f7e0018626bd..71f09a8a00f4 100644 --- a/drivers/gpu/drm/i915/i915_gem_gtt.c +++ b/drivers/gpu/drm/i915/i915_gem_gtt.c @@ -567,12 +567,20 @@ static void i915_gtt_color_adjust(struct drm_mm_node *node, *end -= 4096; } } - void i915_gem_setup_global_gtt(struct drm_device *dev, unsigned long start, unsigned long mappable_end, unsigned long end) { + /* 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. + */ drm_i915_private_t *dev_priv = dev->dev_private; struct drm_mm_node *entry; struct drm_i915_gem_object *obj; @@ -633,12 +641,12 @@ void i915_gem_init_global_gtt(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->gtt.total; mappable_size = dev_priv->gtt.mappable_end; if (intel_enable_ppgtt(dev) && HAS_ALIASING_PPGTT(dev)) { + int ret; /* 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; @@ -646,23 +654,14 @@ void i915_gem_init_global_gtt(struct drm_device *dev) i915_gem_setup_global_gtt(dev, 0, mappable_size, gtt_size); ret = i915_gem_init_aliasing_ppgtt(dev); - if (ret) { - mutex_unlock(&dev->struct_mutex); + if (!ret) return; - } - } 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_setup_global_gtt(dev, 0, mappable_size, gtt_size); + + DRM_ERROR("Aliased PPGTT setup failed %d\n", ret); + drm_mm_takedown(&dev_priv->mm.gtt_space); + gtt_size += I915_PPGTT_PD_ENTRIES*PAGE_SIZE; } + i915_gem_setup_global_gtt(dev, 0, mappable_size, gtt_size); } static int setup_scratch_page(struct drm_device *dev) From f82855d342b6c8483c56e6d2e200a71731509a39 Mon Sep 17 00:00:00 2001 From: Ben Widawsky Date: Tue, 29 Jan 2013 12:00:15 -0800 Subject: [PATCH 090/101] drm/i915: Fix CAGF for HSW The shift changed, hurray. Reported-by: Kenneth Graunke Cc: Paulo Zanoni Reviewed-by: Paulo Zanoni Tested-by: Paulo Zanoni Cc: stable@vger.kernel.org Signed-off-by: Ben Widawsky Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_debugfs.c | 10 +++++++--- drivers/gpu/drm/i915/i915_reg.h | 2 ++ 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_debugfs.c b/drivers/gpu/drm/i915/i915_debugfs.c index 384f19368a1d..749114881c23 100644 --- a/drivers/gpu/drm/i915/i915_debugfs.c +++ b/drivers/gpu/drm/i915/i915_debugfs.c @@ -957,7 +957,7 @@ static int i915_cur_delayinfo(struct seq_file *m, void *unused) u32 gt_perf_status = I915_READ(GEN6_GT_PERF_STATUS); u32 rp_state_limits = I915_READ(GEN6_RP_STATE_LIMITS); u32 rp_state_cap = I915_READ(GEN6_RP_STATE_CAP); - u32 rpstat; + u32 rpstat, cagf; u32 rpupei, rpcurup, rpprevup; u32 rpdownei, rpcurdown, rpprevdown; int max_freq; @@ -976,6 +976,11 @@ static int i915_cur_delayinfo(struct seq_file *m, void *unused) rpdownei = I915_READ(GEN6_RP_CUR_DOWN_EI); rpcurdown = I915_READ(GEN6_RP_CUR_DOWN); rpprevdown = I915_READ(GEN6_RP_PREV_DOWN); + if (IS_HASWELL(dev)) + cagf = (rpstat & HSW_CAGF_MASK) >> HSW_CAGF_SHIFT; + else + cagf = (rpstat & GEN6_CAGF_MASK) >> GEN6_CAGF_SHIFT; + cagf *= GT_FREQUENCY_MULTIPLIER; gen6_gt_force_wake_put(dev_priv); mutex_unlock(&dev->struct_mutex); @@ -988,8 +993,7 @@ static int i915_cur_delayinfo(struct seq_file *m, void *unused) gt_perf_status & 0xff); seq_printf(m, "Render p-state limit: %d\n", rp_state_limits & 0xff); - seq_printf(m, "CAGF: %dMHz\n", ((rpstat & GEN6_CAGF_MASK) >> - GEN6_CAGF_SHIFT) * GT_FREQUENCY_MULTIPLIER); + seq_printf(m, "CAGF: %dMHz\n", cagf); seq_printf(m, "RP CUR UP EI: %dus\n", rpupei & GEN6_CURICONT_MASK); seq_printf(m, "RP CUR UP: %dus\n", rpcurup & diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index 0c89cf5377ea..9a3cd047ad9b 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -4196,7 +4196,9 @@ #define GEN6_RP_INTERRUPT_LIMITS 0xA014 #define GEN6_RPSTAT1 0xA01C #define GEN6_CAGF_SHIFT 8 +#define HSW_CAGF_SHIFT 7 #define GEN6_CAGF_MASK (0x7f << GEN6_CAGF_SHIFT) +#define HSW_CAGF_MASK (0x7f << HSW_CAGF_SHIFT) #define GEN6_RP_CONTROL 0xA024 #define GEN6_RP_MEDIA_TURBO (1<<11) #define GEN6_RP_MEDIA_MODE_MASK (3<<9) From 725a5b54028916cd2511a251c5b5b13d1715addc Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Tue, 8 Jan 2013 11:02:57 +0000 Subject: [PATCH 091/101] drm/i915: Only run idle processing from i915_gem_retire_requests_worker When adding the fb idle detection to mark-inactive, it was forgotten that userspace can drive the processing of retire-requests. We assumed that it would be principally driven by the retire requests worker, running once every second whilst active and so we would get the deferred timer for free. Instead we spend too many CPU cycles reclocking the LVDS preventing real work from being done. Signed-off-by: Chris Wilson Reported-and-tested-by: Alexander Lam Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=58843 Cc: stable@vger.kernel.org Reviewed-by: Rodrigo Vivi Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_gem.c | 3 --- drivers/gpu/drm/i915/intel_display.c | 28 +++++++++++----------------- drivers/gpu/drm/i915/intel_drv.h | 3 +-- 3 files changed, 12 insertions(+), 22 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index 801f77ece72e..d7461771be2d 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -1899,9 +1899,6 @@ i915_gem_object_move_to_inactive(struct drm_i915_gem_object *obj) BUG_ON(obj->base.write_domain & ~I915_GEM_GPU_DOMAINS); BUG_ON(!obj->active); - if (obj->pin_count) /* are we a framebuffer? */ - intel_mark_fb_idle(obj); - list_move_tail(&obj->mm_list, &dev_priv->mm.inactive_list); list_del_init(&obj->ring_list); diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 56c51ddf54ec..0d45487040d2 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -6725,6 +6725,17 @@ void intel_mark_busy(struct drm_device *dev) void intel_mark_idle(struct drm_device *dev) { + struct drm_crtc *crtc; + + if (!i915_powersave) + return; + + list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { + if (!crtc->fb) + continue; + + intel_decrease_pllclock(crtc); + } } void intel_mark_fb_busy(struct drm_i915_gem_object *obj) @@ -6744,23 +6755,6 @@ void intel_mark_fb_busy(struct drm_i915_gem_object *obj) } } -void intel_mark_fb_idle(struct drm_i915_gem_object *obj) -{ - struct drm_device *dev = obj->base.dev; - struct drm_crtc *crtc; - - if (!i915_powersave) - return; - - list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { - if (!crtc->fb) - continue; - - if (to_intel_framebuffer(crtc->fb)->obj == obj) - intel_decrease_pllclock(crtc); - } -} - static void intel_crtc_destroy(struct drm_crtc *crtc) { struct intel_crtc *intel_crtc = to_intel_crtc(crtc); diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index fcdfe42e434c..13afb37d8dec 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -452,9 +452,8 @@ extern bool intel_sdvo_init(struct drm_device *dev, uint32_t sdvo_reg, extern void intel_dvo_init(struct drm_device *dev); extern void intel_tv_init(struct drm_device *dev); extern void intel_mark_busy(struct drm_device *dev); -extern void intel_mark_idle(struct drm_device *dev); extern void intel_mark_fb_busy(struct drm_i915_gem_object *obj); -extern void intel_mark_fb_idle(struct drm_i915_gem_object *obj); +extern void intel_mark_idle(struct drm_device *dev); extern bool intel_lvds_init(struct drm_device *dev); extern bool intel_is_dual_link_lvds(struct drm_device *dev); extern void intel_dp_init(struct drm_device *dev, int output_reg, From 6b25a88752e8e9dc33c700712059b094d3da3219 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Wed, 30 Jan 2013 15:59:57 +0100 Subject: [PATCH 092/101] drm/i915: kill cargo-culted locking from power well code We may not concurrently change the power wells code. Which is already guaranteed since modesets aren't concurrent. That leaves races against setup/teardown/suspend/resume, and for those we already (try) rather hard not to hit concurrent modesets. No debug WARN_ON added since that would require us to grab the modeset locks in init/suspend code. Which is again just cargo culting since just grabbing the locks in those paths isn't good enough, we need the right order of operations, too. Cc: Paulo Zanoni Reviewed-by: Rodrigo Vivi Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_pm.c | 4 ---- 1 file changed, 4 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c index 64d65f564a7c..bec1f9ffba2d 100644 --- a/drivers/gpu/drm/i915/intel_pm.c +++ b/drivers/gpu/drm/i915/intel_pm.c @@ -4088,8 +4088,6 @@ void intel_init_power_well(struct drm_device *dev) if (!IS_HASWELL(dev)) return; - mutex_lock(&dev->struct_mutex); - /* For now, we need the power well to be always enabled. */ intel_set_power_well(dev, true); @@ -4097,8 +4095,6 @@ void intel_init_power_well(struct drm_device *dev) * the driver is in charge now. */ if (I915_READ(HSW_PWR_WELL_BIOS) & HSW_PWR_WELL_ENABLE) I915_WRITE(HSW_PWR_WELL_BIOS, 0); - - mutex_unlock(&dev->struct_mutex); } /* Set up chip specific power management-related functions */ From d5f21e4072645d0174ed4cc7197e0e30f84f96a2 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Wed, 30 Jan 2013 15:59:56 +0100 Subject: [PATCH 093/101] drm/i915: don't run hsw power well code on !hsw Dumps annoying noise into the dmesg: [drm:intel_set_power_well] *ERROR* Timeout enabling power well Reported-by: Sedat Dilek Cc: Sedat Dilek Cc: Paulo Zanoni Tested-by: Sedat Dilek Reviewed-by: Paulo Zanoni Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_pm.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c index bec1f9ffba2d..f024e7dcc2c7 100644 --- a/drivers/gpu/drm/i915/intel_pm.c +++ b/drivers/gpu/drm/i915/intel_pm.c @@ -4053,6 +4053,9 @@ void intel_set_power_well(struct drm_device *dev, bool enable) bool is_enabled, enable_requested; uint32_t tmp; + if (!IS_HASWELL(dev)) + return; + tmp = I915_READ(HSW_PWR_WELL_DRIVER); is_enabled = tmp & HSW_PWR_WELL_STATE; enable_requested = tmp & HSW_PWR_WELL_ENABLE; From 10aa17c86f0de1fd902f7b8ee487a3682d7401df Mon Sep 17 00:00:00 2001 From: Paulo Zanoni Date: Tue, 29 Jan 2013 16:35:18 -0200 Subject: [PATCH 094/101] drm/i915: don't send DP "idle" pattern before "normal" on HSW PORT_A The DP_TP_STATUS register for PORT_A doesn't exist. Our documentation will be fixed soon, so the code does not match it for now. This solves "Timed out waiting for DP idle patterns" and "unclaimed register" messages on eDP. V1: Was called "drm/i915: don't read DP_TP_STATUS(PORT_A)" V2: Was called "drm/i915: don't send DP idle pattern before normal pattern on HSW" V3: Only change the code that touches PORT_A. Signed-off-by: Paulo Zanoni Reviewed-by: Jani Nikula Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_dp.c | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c index 51fd79758368..1b76b04787c7 100644 --- a/drivers/gpu/drm/i915/intel_dp.c +++ b/drivers/gpu/drm/i915/intel_dp.c @@ -1785,14 +1785,18 @@ intel_dp_set_link_train(struct intel_dp *intel_dp, temp &= ~DP_TP_CTL_LINK_TRAIN_MASK; switch (dp_train_pat & DP_TRAINING_PATTERN_MASK) { case DP_TRAINING_PATTERN_DISABLE: - temp |= DP_TP_CTL_LINK_TRAIN_IDLE; - I915_WRITE(DP_TP_CTL(port), temp); - if (wait_for((I915_READ(DP_TP_STATUS(port)) & - DP_TP_STATUS_IDLE_DONE), 1)) - DRM_ERROR("Timed out waiting for DP idle patterns\n"); + if (port != PORT_A) { + temp |= DP_TP_CTL_LINK_TRAIN_IDLE; + I915_WRITE(DP_TP_CTL(port), temp); + + if (wait_for((I915_READ(DP_TP_STATUS(port)) & + DP_TP_STATUS_IDLE_DONE), 1)) + DRM_ERROR("Timed out waiting for DP idle patterns\n"); + + temp &= ~DP_TP_CTL_LINK_TRAIN_MASK; + } - temp &= ~DP_TP_CTL_LINK_TRAIN_MASK; temp |= DP_TP_CTL_LINK_TRAIN_NORMAL; break; From 693101618a4beedf1b3d291860aee56c5fe44a1c Mon Sep 17 00:00:00 2001 From: Paulo Zanoni Date: Tue, 29 Jan 2013 16:35:19 -0200 Subject: [PATCH 095/101] drm/i915: check the power down well on assert_pipe() If the power well is disabled, we should not try to read its registers, otherwise we'll get "unclaimed register" messages. V2: Don't check whether the power well is enabled or not, just check whether we asked it to be enabled or not: if we asked to disable the power well, don't use the registers on it, even if it's still enabled. V3: Fix bug that breaks all non-Haswell machines. Signed-off-by: Paulo Zanoni Reviewed-by: Jani Nikula Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_display.c | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 0d45487040d2..429b66bcb5b2 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -1214,9 +1214,15 @@ void assert_pipe(struct drm_i915_private *dev_priv, if (pipe == PIPE_A && dev_priv->quirks & QUIRK_PIPEA_FORCE) state = true; - reg = PIPECONF(cpu_transcoder); - val = I915_READ(reg); - cur_state = !!(val & PIPECONF_ENABLE); + if (IS_HASWELL(dev_priv->dev) && cpu_transcoder != TRANSCODER_EDP && + !(I915_READ(HSW_PWR_WELL_DRIVER) & HSW_PWR_WELL_ENABLE)) { + cur_state = false; + } else { + reg = PIPECONF(cpu_transcoder); + val = I915_READ(reg); + cur_state = !!(val & PIPECONF_ENABLE); + } + WARN(cur_state != state, "pipe %c assertion failure (expected %s, current %s)\n", pipe_name(pipe), state_string(state), state_string(cur_state)); From d6dd9eb1d96d2b7345fe4664066c2b7ed86da898 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Tue, 29 Jan 2013 16:35:20 -0200 Subject: [PATCH 096/101] drm/i915: dynamic Haswell display power well support We can disable (almost) all the display hw if we only use pipe A, with the integrated edp transcoder on port A. Because we don't set the cpu transcoder that early (yet), we need to help us with a trick to simply check for any edp encoders. v2: Paulo Zanoni pointed out that we also need to configure the eDP cpu transcoder correctly. v3: Made by Paulo Zanoni - Rebase patch to be on top of "fix intel_init_power_wells" patch - Fix typos - Fix a small bug by adding a "connectors_active" check - Restore the initial code that unconditionally enables the power well when taking over from the BIOS v4: Made by Paulo Zanoni - One more typo spotted by Jani Nikula v5: Made by Paulo Zanoni - Rebase Signed-off-by: Paulo Zanoni Reviewed-by: Jani Nikula Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_ddi.c | 8 ++++++- drivers/gpu/drm/i915/intel_display.c | 31 ++++++++++++++++++++++++++++ 2 files changed, 38 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/intel_ddi.c b/drivers/gpu/drm/i915/intel_ddi.c index 33b911218023..cedf4ab5ff16 100644 --- a/drivers/gpu/drm/i915/intel_ddi.c +++ b/drivers/gpu/drm/i915/intel_ddi.c @@ -988,7 +988,13 @@ void intel_ddi_enable_pipe_func(struct drm_crtc *crtc) if (cpu_transcoder == TRANSCODER_EDP) { switch (pipe) { case PIPE_A: - temp |= TRANS_DDI_EDP_INPUT_A_ONOFF; + /* Can only use the always-on power well for eDP when + * not using the panel fitter, and when not using motion + * blur mitigation (which we don't support). */ + if (dev_priv->pch_pf_size) + temp |= TRANS_DDI_EDP_INPUT_A_ONOFF; + else + temp |= TRANS_DDI_EDP_INPUT_A_ON; break; case PIPE_B: temp |= TRANS_DDI_EDP_INPUT_B_ONOFF; diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 429b66bcb5b2..1f1d045912fb 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -5607,6 +5607,35 @@ static int ironlake_crtc_mode_set(struct drm_crtc *crtc, return fdi_config_ok ? ret : -EINVAL; } +static void haswell_modeset_global_resources(struct drm_device *dev) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + bool enable = false; + struct intel_crtc *crtc; + struct intel_encoder *encoder; + + list_for_each_entry(crtc, &dev->mode_config.crtc_list, base.head) { + if (crtc->pipe != PIPE_A && crtc->base.enabled) + enable = true; + /* XXX: Should check for edp transcoder here, but thanks to init + * sequence that's not yet available. Just in case desktop eDP + * on PORT D is possible on haswell, too. */ + } + + list_for_each_entry(encoder, &dev->mode_config.encoder_list, + base.head) { + if (encoder->type != INTEL_OUTPUT_EDP && + encoder->connectors_active) + enable = true; + } + + /* Even the eDP panel fitter is outside the always-on well. */ + if (dev_priv->pch_pf_size) + enable = true; + + intel_set_power_well(dev, enable); +} + static int haswell_crtc_mode_set(struct drm_crtc *crtc, struct drm_display_mode *mode, struct drm_display_mode *adjusted_mode, @@ -8480,6 +8509,8 @@ static void intel_init_display(struct drm_device *dev) } else if (IS_HASWELL(dev)) { dev_priv->display.fdi_link_train = hsw_fdi_link_train; dev_priv->display.write_eld = haswell_write_eld; + dev_priv->display.modeset_global_resources = + haswell_modeset_global_resources; } } else if (IS_G4X(dev)) { dev_priv->display.write_eld = g4x_write_eld; From d93c6233543cdab83eca4d0590737c3e99314fd6 Mon Sep 17 00:00:00 2001 From: Changlong Xie Date: Thu, 31 Jan 2013 11:32:50 +0800 Subject: [PATCH 097/101] drm/i915: gen6_gmch_remove can be static Signed-off-by: Changlong Xie Reported-by: Fengguang Wu Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_gem_gtt.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/i915_gem_gtt.c b/drivers/gpu/drm/i915/i915_gem_gtt.c index 71f09a8a00f4..bdaca3f47988 100644 --- a/drivers/gpu/drm/i915/i915_gem_gtt.c +++ b/drivers/gpu/drm/i915/i915_gem_gtt.c @@ -773,7 +773,7 @@ static int gen6_gmch_probe(struct drm_device *dev, return ret; } -void gen6_gmch_remove(struct drm_device *dev) +static void gen6_gmch_remove(struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; iounmap(dev_priv->gtt.gsm); From 766aa1c42362eafc53f5939cd3f83113e9d062ed Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Fri, 25 Jan 2013 21:44:46 +0200 Subject: [PATCH 098/101] drm/i915: Introduce i915_vgacntrl_reg() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The VGACNTRL register has moved around between different platforms. To handle the differences add i915_vgacntrl_reg() which returns the correct offset for the VGACNTRL register. Signed-off-by: Ville Syrjälä Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_drv.h | 10 ++++++++++ drivers/gpu/drm/i915/i915_reg.h | 2 ++ drivers/gpu/drm/i915/i915_suspend.c | 10 ++-------- drivers/gpu/drm/i915/intel_display.c | 14 ++------------ 4 files changed, 16 insertions(+), 20 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index d3274164143d..984523d809a8 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -1887,4 +1887,14 @@ __i915_write(64, q) #define INTEL_BROADCAST_RGB_FULL 1 #define INTEL_BROADCAST_RGB_LIMITED 2 +static inline uint32_t i915_vgacntrl_reg(struct drm_device *dev) +{ + if (HAS_PCH_SPLIT(dev)) + return CPU_VGACNTRL; + else if (IS_VALLEYVIEW(dev)) + return VLV_VGACNTRL; + else + return VGACNTRL; +} + #endif diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index 9a3cd047ad9b..e2b592a68f58 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -3238,6 +3238,8 @@ # define VGA_2X_MODE (1 << 30) # define VGA_PIPE_B_SELECT (1 << 29) +#define VLV_VGACNTRL (VLV_DISPLAY_BASE + 0x71400) + /* Ironlake */ #define CPU_VGACNTRL 0x41000 diff --git a/drivers/gpu/drm/i915/i915_suspend.c b/drivers/gpu/drm/i915/i915_suspend.c index 3911e0450bbe..2135f21ea458 100644 --- a/drivers/gpu/drm/i915/i915_suspend.c +++ b/drivers/gpu/drm/i915/i915_suspend.c @@ -73,10 +73,7 @@ static void i915_save_vga(struct drm_device *dev) dev_priv->regfile.saveVGA0 = I915_READ(VGA0); dev_priv->regfile.saveVGA1 = I915_READ(VGA1); dev_priv->regfile.saveVGA_PD = I915_READ(VGA_PD); - if (HAS_PCH_SPLIT(dev)) - dev_priv->regfile.saveVGACNTRL = I915_READ(CPU_VGACNTRL); - else - dev_priv->regfile.saveVGACNTRL = I915_READ(VGACNTRL); + dev_priv->regfile.saveVGACNTRL = I915_READ(i915_vgacntrl_reg(dev)); /* VGA color palette registers */ dev_priv->regfile.saveDACMASK = I915_READ8(VGA_DACMASK); @@ -137,10 +134,7 @@ static void i915_restore_vga(struct drm_device *dev) u16 cr_index, cr_data, st01; /* VGA state */ - if (HAS_PCH_SPLIT(dev)) - I915_WRITE(CPU_VGACNTRL, dev_priv->regfile.saveVGACNTRL); - else - I915_WRITE(VGACNTRL, dev_priv->regfile.saveVGACNTRL); + I915_WRITE(i915_vgacntrl_reg(dev), dev_priv->regfile.saveVGACNTRL); I915_WRITE(VGA0, dev_priv->regfile.saveVGA0); I915_WRITE(VGA1, dev_priv->regfile.saveVGA1); diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 1f1d045912fb..62f45907e4df 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -8670,12 +8670,7 @@ static void i915_disable_vga(struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; u8 sr1; - u32 vga_reg; - - if (HAS_PCH_SPLIT(dev)) - vga_reg = CPU_VGACNTRL; - else - vga_reg = VGACNTRL; + u32 vga_reg = i915_vgacntrl_reg(dev); vga_get_uninterruptible(dev->pdev, VGA_RSRC_LEGACY_IO); outb(SR01, VGA_SR_INDEX); @@ -8937,12 +8932,7 @@ static void intel_sanitize_encoder(struct intel_encoder *encoder) void i915_redisable_vga(struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; - u32 vga_reg; - - if (HAS_PCH_SPLIT(dev)) - vga_reg = CPU_VGACNTRL; - else - vga_reg = VGACNTRL; + u32 vga_reg = i915_vgacntrl_reg(dev); if (I915_READ(vga_reg) != VGA_DISP_DISABLE) { DRM_DEBUG_KMS("Something enabled VGA plane, disabling it\n"); From fe31b574fb2563f3aaa24dec302ddd0a033cda0f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Fri, 25 Jan 2013 21:44:47 +0200 Subject: [PATCH 099/101] drm/i915: Kill IS_DISPLAYREG() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit All display registers should now include the proper offset on VLV. That means IS_DISPLAYREG() is now useless, and we can eliminate it. Signed-off-by: Ville Syrjälä Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_drv.c | 104 +------------------------------- 1 file changed, 1 insertion(+), 103 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_drv.c b/drivers/gpu/drm/i915/i915_drv.c index 9cc8f8780cf8..d159d7a402e9 100644 --- a/drivers/gpu/drm/i915/i915_drv.c +++ b/drivers/gpu/drm/i915/i915_drv.c @@ -1119,102 +1119,6 @@ MODULE_LICENSE("GPL and additional rights"); ((HAS_FORCE_WAKE((dev_priv)->dev)) && \ ((reg) < 0x40000) && \ ((reg) != FORCEWAKE)) - -static bool IS_DISPLAYREG(u32 reg) -{ - /* - * This should make it easier to transition modules over to the - * new register block scheme, since we can do it incrementally. - */ - if (reg >= VLV_DISPLAY_BASE) - return false; - - if (reg >= RENDER_RING_BASE && - reg < RENDER_RING_BASE + 0xff) - return false; - if (reg >= GEN6_BSD_RING_BASE && - reg < GEN6_BSD_RING_BASE + 0xff) - return false; - if (reg >= BLT_RING_BASE && - reg < BLT_RING_BASE + 0xff) - return false; - - if (reg == PGTBL_ER) - return false; - - if (reg >= IPEIR_I965 && - reg < HWSTAM) - return false; - - if (reg == MI_MODE) - return false; - - if (reg == GFX_MODE_GEN7) - return false; - - if (reg == RENDER_HWS_PGA_GEN7 || - reg == BSD_HWS_PGA_GEN7 || - reg == BLT_HWS_PGA_GEN7) - return false; - - if (reg == GEN6_BSD_SLEEP_PSMI_CONTROL || - reg == GEN6_BSD_RNCID) - return false; - - if (reg == GEN6_BLITTER_ECOSKPD) - return false; - - if (reg >= 0x4000c && - reg <= 0x4002c) - return false; - - if (reg >= 0x4f000 && - reg <= 0x4f08f) - return false; - - if (reg >= 0x4f100 && - reg <= 0x4f11f) - return false; - - if (reg >= VLV_MASTER_IER && - reg <= GEN6_PMIER) - return false; - - if (reg >= FENCE_REG_SANDYBRIDGE_0 && - reg < (FENCE_REG_SANDYBRIDGE_0 + (16*8))) - return false; - - if (reg >= VLV_IIR_RW && - reg <= VLV_ISR) - return false; - - if (reg == FORCEWAKE_VLV || - reg == FORCEWAKE_ACK_VLV) - return false; - - if (reg == GEN6_GDRST) - return false; - - switch (reg) { - case _3D_CHICKEN3: - case IVB_CHICKEN3: - case GEN7_COMMON_SLICE_CHICKEN1: - case GEN7_L3CNTLREG1: - case GEN7_L3_CHICKEN_MODE_REGISTER: - case GEN7_ROW_CHICKEN2: - case GEN7_L3SQCREG4: - case GEN7_SQ_CHICKEN_MBCUNIT_CONFIG: - case GEN7_HALF_SLICE_CHICKEN1: - case GEN6_MBCTL: - case GEN6_UCGCTL2: - return false; - default: - break; - } - - return true; -} - static void ilk_dummy_write(struct drm_i915_private *dev_priv) { @@ -1238,8 +1142,6 @@ u##x i915_read##x(struct drm_i915_private *dev_priv, u32 reg) { \ if (dev_priv->forcewake_count == 0) \ dev_priv->gt.force_wake_put(dev_priv); \ spin_unlock_irqrestore(&dev_priv->gt_lock, irqflags); \ - } else if (IS_VALLEYVIEW(dev_priv->dev) && IS_DISPLAYREG(reg)) { \ - val = read##y(dev_priv->regs + reg + 0x180000); \ } else { \ val = read##y(dev_priv->regs + reg); \ } \ @@ -1266,11 +1168,7 @@ void i915_write##x(struct drm_i915_private *dev_priv, u32 reg, u##x val) { \ DRM_ERROR("Unknown unclaimed register before writing to %x\n", reg); \ I915_WRITE_NOTRACE(GEN7_ERR_INT, ERR_INT_MMIO_UNCLAIMED); \ } \ - if (IS_VALLEYVIEW(dev_priv->dev) && IS_DISPLAYREG(reg)) { \ - write##y(val, dev_priv->regs + reg + 0x180000); \ - } else { \ - write##y(val, dev_priv->regs + reg); \ - } \ + write##y(val, dev_priv->regs + reg); \ if (unlikely(__fifo_ret)) { \ gen6_gt_check_fifodbg(dev_priv); \ } \ From 209d52110a32c2069b5d870504e73fdb0e30fc51 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Fri, 25 Jan 2013 21:44:48 +0200 Subject: [PATCH 100/101] drm/i915: Set the SR01 "screen off" bit in i915_redisable_vga() too MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit From BSpec / SR01 - Clocking Mode: "The following sequence must be used when disabling the VGA plane. Write SR01 to set bit 5 = 1 to disable video output. Wait for 100us. Disable the VGA plane via Bit 31 of the MMIO VGA control." So simply call i915_disable_vga() from i915_redisable_vga(). Signed-off-by: Ville Syrjälä Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_display.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 62f45907e4df..d75c6a0a4bd6 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -8936,8 +8936,7 @@ void i915_redisable_vga(struct drm_device *dev) if (I915_READ(vga_reg) != VGA_DISP_DISABLE) { DRM_DEBUG_KMS("Something enabled VGA plane, disabling it\n"); - I915_WRITE(vga_reg, VGA_DISP_DISABLE); - POSTING_READ(vga_reg); + i915_disable_vga(dev); } } From 7d37beaaf3dbc6ff16f4d32a4dd6f8c557c6ab50 Mon Sep 17 00:00:00 2001 From: Yasuaki Ishimatsu Date: Fri, 1 Feb 2013 10:14:20 +0900 Subject: [PATCH 101/101] GPU/i915: Fix acpi_bus_get_device() check in drivers/gpu/drm/i915/intel_opregion.c acpi_bus_get_device() returns int not acpi_status. The patch change not to apply ACPI_FAILURE() to the return value of acpi_bus_get_device(). Signed-off-by: Yasuaki Ishimatsu Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_opregion.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/intel_opregion.c b/drivers/gpu/drm/i915/intel_opregion.c index 7741c22c934c..4d338740f2cb 100644 --- a/drivers/gpu/drm/i915/intel_opregion.c +++ b/drivers/gpu/drm/i915/intel_opregion.c @@ -347,7 +347,7 @@ static void intel_didl_outputs(struct drm_device *dev) int i = 0; handle = DEVICE_ACPI_HANDLE(&dev->pdev->dev); - if (!handle || ACPI_FAILURE(acpi_bus_get_device(handle, &acpi_dev))) + if (!handle || acpi_bus_get_device(handle, &acpi_dev)) return; if (acpi_is_video_device(acpi_dev))