From f43f627d2f17e95c78647eeddf968d12f5c286b1 Mon Sep 17 00:00:00 2001 From: Jesse Barnes Date: Mon, 4 Feb 2013 13:37:20 +0000 Subject: [PATCH 01/79] PM: make VT switching to the suspend console optional v3 KMS drivers can potentially restore the display configuration without userspace help. Such drivers can can call a new funciton, pm_vt_switch_required(false) if they support this feature. In that case, the PM layer won't VT switch to the suspend console at suspend time and then back to the original VT on resume, but rather leave things alone for a nicer looking suspend and resume sequence. v2: make a function so we can handle multiple drivers (Alan) v3: use a list to track device requests (Rafael) v4: Squash in build fix from Jesse for CONFIG_VT_CONSOLE_SLEEP=n v5: Squash in patch from Wu Fengguang to add a few missing static qualifiers. v6: Add missing EXPORT_SYMBOL. Signed-off-by: Jesse Barnes Reviewed-by: Rafael J. Wysocki (v3) Signed-off-by: Daniel Vetter --- include/linux/pm.h | 13 +++++ kernel/power/console.c | 116 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 129 insertions(+) diff --git a/include/linux/pm.h b/include/linux/pm.h index 03d7bb145311..e5da2f353e8f 100644 --- a/include/linux/pm.h +++ b/include/linux/pm.h @@ -35,6 +35,19 @@ extern void (*pm_idle)(void); extern void (*pm_power_off)(void); extern void (*pm_power_off_prepare)(void); +struct device; /* we have a circular dep with device.h */ +#ifdef CONFIG_VT_CONSOLE_SLEEP +extern void pm_vt_switch_required(struct device *dev, bool required); +extern void pm_vt_switch_unregister(struct device *dev); +#else +static inline void pm_vt_switch_required(struct device *dev, bool required) +{ +} +static inline void pm_vt_switch_unregister(struct device *dev) +{ +} +#endif /* CONFIG_VT_CONSOLE_SLEEP */ + /* * Device power management */ diff --git a/kernel/power/console.c b/kernel/power/console.c index b1dc456474b5..463aa6736751 100644 --- a/kernel/power/console.c +++ b/kernel/power/console.c @@ -4,6 +4,7 @@ * Originally from swsusp. */ +#include #include #include #include @@ -14,8 +15,120 @@ static int orig_fgconsole, orig_kmsg; +static DEFINE_MUTEX(vt_switch_mutex); + +struct pm_vt_switch { + struct list_head head; + struct device *dev; + bool required; +}; + +static LIST_HEAD(pm_vt_switch_list); + + +/** + * pm_vt_switch_required - indicate VT switch at suspend requirements + * @dev: device + * @required: if true, caller needs VT switch at suspend/resume time + * + * The different console drivers may or may not require VT switches across + * suspend/resume, depending on how they handle restoring video state and + * what may be running. + * + * Drivers can indicate support for switchless suspend/resume, which can + * save time and flicker, by using this routine and passing 'false' as + * the argument. If any loaded driver needs VT switching, or the + * no_console_suspend argument has been passed on the command line, VT + * switches will occur. + */ +void pm_vt_switch_required(struct device *dev, bool required) +{ + struct pm_vt_switch *entry, *tmp; + + mutex_lock(&vt_switch_mutex); + list_for_each_entry(tmp, &pm_vt_switch_list, head) { + if (tmp->dev == dev) { + /* already registered, update requirement */ + tmp->required = required; + goto out; + } + } + + entry = kmalloc(sizeof(*entry), GFP_KERNEL); + if (!entry) + goto out; + + entry->required = required; + entry->dev = dev; + + list_add(&entry->head, &pm_vt_switch_list); +out: + mutex_unlock(&vt_switch_mutex); +} +EXPORT_SYMBOL(pm_vt_switch_required); + +/** + * pm_vt_switch_unregister - stop tracking a device's VT switching needs + * @dev: device + * + * Remove @dev from the vt switch list. + */ +void pm_vt_switch_unregister(struct device *dev) +{ + struct pm_vt_switch *tmp; + + mutex_lock(&vt_switch_mutex); + list_for_each_entry(tmp, &pm_vt_switch_list, head) { + if (tmp->dev == dev) { + list_del(&tmp->head); + break; + } + } + mutex_unlock(&vt_switch_mutex); +} +EXPORT_SYMBOL(pm_vt_switch_unregister); + +/* + * There are three cases when a VT switch on suspend/resume are required: + * 1) no driver has indicated a requirement one way or another, so preserve + * the old behavior + * 2) console suspend is disabled, we want to see debug messages across + * suspend/resume + * 3) any registered driver indicates it needs a VT switch + * + * If none of these conditions is present, meaning we have at least one driver + * that doesn't need the switch, and none that do, we can avoid it to make + * resume look a little prettier (and suspend too, but that's usually hidden, + * e.g. when closing the lid on a laptop). + */ +static bool pm_vt_switch(void) +{ + struct pm_vt_switch *entry; + bool ret = true; + + mutex_lock(&vt_switch_mutex); + if (list_empty(&pm_vt_switch_list)) + goto out; + + if (!console_suspend_enabled) + goto out; + + list_for_each_entry(entry, &pm_vt_switch_list, head) { + if (entry->required) + goto out; + } + + ret = false; +out: + mutex_unlock(&vt_switch_mutex); + return ret; +} + int pm_prepare_console(void) { + if (!pm_vt_switch()) + return 0; + orig_fgconsole = vt_move_to_console(SUSPEND_CONSOLE, 1); if (orig_fgconsole < 0) return 1; @@ -26,6 +139,9 @@ int pm_prepare_console(void) void pm_restore_console(void) { + if (!pm_vt_switch()) + return; + if (orig_fgconsole >= 0) { vt_move_to_console(orig_fgconsole, 0); vt_kmsg_redirect(orig_kmsg); From 3cf2667b9f8b2c2fe298a427deb399e52321da6b Mon Sep 17 00:00:00 2001 From: Jesse Barnes Date: Mon, 4 Feb 2013 13:37:21 +0000 Subject: [PATCH 02/79] fb: add support for drivers not needing VT switch at suspend/resume time Use the new PM routines to indicate whether we need to VT switch at suspend and resume time. When a new driver is bound, set its flag accordingly, and when unbound, remove it from the PM's console tracking list. Signed-off-by: Jesse Barnes Acked-by: Rafael J. Wysocki Signed-off-by: Daniel Vetter --- drivers/video/fbmem.c | 7 +++++++ include/linux/fb.h | 2 ++ 2 files changed, 9 insertions(+) diff --git a/drivers/video/fbmem.c b/drivers/video/fbmem.c index dc61c12ecf8c..2af7153da2e4 100644 --- a/drivers/video/fbmem.c +++ b/drivers/video/fbmem.c @@ -1645,6 +1645,11 @@ static int do_register_framebuffer(struct fb_info *fb_info) if (!fb_info->modelist.prev || !fb_info->modelist.next) INIT_LIST_HEAD(&fb_info->modelist); + if (fb_info->skip_vt_switch) + pm_vt_switch_required(fb_info->dev, false); + else + pm_vt_switch_required(fb_info->dev, true); + fb_var_to_videomode(&mode, &fb_info->var); fb_add_videomode(&mode, &fb_info->modelist); registered_fb[i] = fb_info; @@ -1679,6 +1684,8 @@ static int do_unregister_framebuffer(struct fb_info *fb_info) if (ret) return -EINVAL; + pm_vt_switch_unregister(fb_info->dev); + unlink_framebuffer(fb_info); if (fb_info->pixmap.addr && (fb_info->pixmap.flags & FB_PIXMAP_DEFAULT)) diff --git a/include/linux/fb.h b/include/linux/fb.h index 58b98606ac26..d49c60f5aa4c 100644 --- a/include/linux/fb.h +++ b/include/linux/fb.h @@ -501,6 +501,8 @@ struct fb_info { resource_size_t size; } ranges[0]; } *apertures; + + bool skip_vt_switch; /* no VT switch on suspend/resume required */ }; static inline struct apertures_struct *alloc_apertures(unsigned int max_num) { From c4aaf3501ee4f86f3dce1120e4bcff32c683a26c Mon Sep 17 00:00:00 2001 From: Damien Lespiau Date: Mon, 18 Feb 2013 16:47:42 +0000 Subject: [PATCH 03/79] drm/i915: Remove platforms in the preliminary_hw_support description We already managed to get it out of sync (Haswell has been promoted out of this option), so let's remove all mentions to platforms. Signed-off-by: Damien Lespiau Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_drv.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_drv.c b/drivers/gpu/drm/i915/i915_drv.c index c5b8c81b9440..857dd2ce30aa 100644 --- a/drivers/gpu/drm/i915/i915_drv.c +++ b/drivers/gpu/drm/i915/i915_drv.c @@ -121,9 +121,7 @@ MODULE_PARM_DESC(i915_enable_ppgtt, unsigned int i915_preliminary_hw_support __read_mostly = 0; module_param_named(preliminary_hw_support, i915_preliminary_hw_support, int, 0600); MODULE_PARM_DESC(preliminary_hw_support, - "Enable preliminary hardware support. " - "Enable Haswell and ValleyView Support. " - "(default: false)"); + "Enable preliminary hardware support. (default: false)"); static struct drm_driver driver; extern int intel_agp_enabled; From 4878cae22a2405b6d33318e2dc99a9c1367fee44 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Mon, 18 Feb 2013 19:08:48 +0200 Subject: [PATCH 04/79] drm/i915: Really wait for pending flips when panning MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Since obj->pending_flips was never set, intel_pipe_set_base() never actually waited for pending page flips to complete. We really do want to wait for the pending flips, because otherwise the mmio surface base address update could overtake the flip, and you could end up with an old frame on the screen once the flip really completes. Just call intel_crtc_wait_pending_flips() prior to calling intel_pipe_set_base() instead of calling just intel_finish_fb() from intel_pipe_set_base(). Moving the call outside of intel_pipe_set_base() avoids calling it twice from the full modeset path. v2: Wait for pending flips w/o holding struct_mutex Signed-off-by: Ville Syrjälä Reviewed-by: Chris Wilson Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_display.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 6eb3882ba9bf..85bf178bac75 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -2301,9 +2301,6 @@ intel_pipe_set_base(struct drm_crtc *crtc, int x, int y, return ret; } - if (crtc->fb) - intel_finish_fb(crtc->fb); - ret = dev_priv->display.update_plane(crtc, fb, x, y); if (ret) { intel_unpin_fb_obj(to_intel_framebuffer(fb)->obj); @@ -8125,6 +8122,8 @@ static int intel_crtc_set_config(struct drm_mode_set *set) goto fail; } } else if (config->fb_changed) { + intel_crtc_wait_for_pending_flips(set->crtc); + ret = intel_pipe_set_base(set->crtc, set->x, set->y, set->fb); } From 96a02917a0131e52efefde49c2784c0421d6c439 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Mon, 18 Feb 2013 19:08:49 +0200 Subject: [PATCH 05/79] drm/i915: Finish page flips and update primary planes after a GPU reset MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit GPU reset will drop all flips that are still in the ring. So after the reset, call update_plane() for all CRTCs to make sure the primary planes are scanning out from the correct buffer. Also finish all pending flips. That means user space will get its page flip events and won't get stuck waiting for them. v2: Explicitly finish page flips instead of relying on FLIP_DONE interrupt being generated by the base address update. v3: Make two loops over crtcs to avoid deadlocks with the crtc mutex Signed-off-by: Ville Syrjälä Reviewed-by: Chris Wilson [danvet: Fixup long line complaint from checkpatch.] Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_irq.c | 2 ++ drivers/gpu/drm/i915/intel_display.c | 38 ++++++++++++++++++++++++++++ drivers/gpu/drm/i915/intel_drv.h | 2 ++ 3 files changed, 42 insertions(+) diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c index 2cd97d1cc920..9fde49a29999 100644 --- a/drivers/gpu/drm/i915/i915_irq.c +++ b/drivers/gpu/drm/i915/i915_irq.c @@ -915,6 +915,8 @@ static void i915_error_work_func(struct work_struct *work) for_each_ring(ring, dev_priv, i) wake_up_all(&ring->irq_queue); + intel_display_handle_reset(dev); + wake_up_all(&dev_priv->gpu_error.reset_queue); } } diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 85bf178bac75..ba8307dc03be 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -2218,6 +2218,44 @@ intel_pipe_set_base_atomic(struct drm_crtc *crtc, struct drm_framebuffer *fb, return dev_priv->display.update_plane(crtc, fb, x, y); } +void intel_display_handle_reset(struct drm_device *dev) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + struct drm_crtc *crtc; + + /* + * Flips in the rings have been nuked by the reset, + * so complete all pending flips so that user space + * will get its events and not get stuck. + * + * Also update the base address of all primary + * planes to the the last fb to make sure we're + * showing the correct fb after a reset. + * + * Need to make two loops over the crtcs so that we + * don't try to grab a crtc mutex before the + * pending_flip_queue really got woken up. + */ + + list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { + struct intel_crtc *intel_crtc = to_intel_crtc(crtc); + enum plane plane = intel_crtc->plane; + + intel_prepare_page_flip(dev, plane); + intel_finish_page_flip_plane(dev, plane); + } + + list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { + struct intel_crtc *intel_crtc = to_intel_crtc(crtc); + + mutex_lock(&crtc->mutex); + if (intel_crtc->active) + dev_priv->display.update_plane(crtc, crtc->fb, + crtc->x, crtc->y); + mutex_unlock(&crtc->mutex); + } +} + static int intel_finish_fb(struct drm_framebuffer *old_fb) { diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index 005a91f1f8f5..febed9a010da 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -695,4 +695,6 @@ extern bool intel_ddi_connector_get_hw_state(struct intel_connector *intel_connector); extern void intel_ddi_fdi_disable(struct drm_crtc *crtc); +extern void intel_display_handle_reset(struct drm_device *dev); + #endif /* __INTEL_DRV_H__ */ From 3e2a155606a0dbe647b87423665fb691941c2fe0 Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Thu, 14 Feb 2013 10:42:11 +0200 Subject: [PATCH 06/79] drm/i915: add \n to the end of sysfs attributes It is customary to end sysfs attributes with a newline. Signed-off-by: Jani Nikula Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_sysfs.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_sysfs.c b/drivers/gpu/drm/i915/i915_sysfs.c index 9462081b1e60..a3a3e22f1a84 100644 --- a/drivers/gpu/drm/i915/i915_sysfs.c +++ b/drivers/gpu/drm/i915/i915_sysfs.c @@ -49,7 +49,7 @@ static ssize_t show_rc6_mask(struct device *kdev, struct device_attribute *attr, char *buf) { struct drm_minor *dminor = container_of(kdev, struct drm_minor, kdev); - return snprintf(buf, PAGE_SIZE, "%x", intel_enable_rc6(dminor->dev)); + return snprintf(buf, PAGE_SIZE, "%x\n", intel_enable_rc6(dminor->dev)); } static ssize_t @@ -57,7 +57,7 @@ show_rc6_ms(struct device *kdev, struct device_attribute *attr, char *buf) { struct drm_minor *dminor = container_of(kdev, struct drm_minor, kdev); u32 rc6_residency = calc_residency(dminor->dev, GEN6_GT_GFX_RC6); - return snprintf(buf, PAGE_SIZE, "%u", rc6_residency); + return snprintf(buf, PAGE_SIZE, "%u\n", rc6_residency); } static ssize_t @@ -65,7 +65,7 @@ show_rc6p_ms(struct device *kdev, struct device_attribute *attr, char *buf) { struct drm_minor *dminor = container_of(kdev, struct drm_minor, kdev); u32 rc6p_residency = calc_residency(dminor->dev, GEN6_GT_GFX_RC6p); - return snprintf(buf, PAGE_SIZE, "%u", rc6p_residency); + return snprintf(buf, PAGE_SIZE, "%u\n", rc6p_residency); } static ssize_t @@ -73,7 +73,7 @@ show_rc6pp_ms(struct device *kdev, struct device_attribute *attr, char *buf) { struct drm_minor *dminor = container_of(kdev, struct drm_minor, kdev); u32 rc6pp_residency = calc_residency(dminor->dev, GEN6_GT_GFX_RC6pp); - return snprintf(buf, PAGE_SIZE, "%u", rc6pp_residency); + return snprintf(buf, PAGE_SIZE, "%u\n", rc6pp_residency); } static DEVICE_ATTR(rc6_enable, S_IRUGO, show_rc6_mask, NULL); @@ -215,7 +215,7 @@ static ssize_t gt_cur_freq_mhz_show(struct device *kdev, ret = dev_priv->rps.cur_delay * GT_FREQUENCY_MULTIPLIER; mutex_unlock(&dev_priv->rps.hw_lock); - return snprintf(buf, PAGE_SIZE, "%d", ret); + return snprintf(buf, PAGE_SIZE, "%d\n", ret); } static ssize_t gt_max_freq_mhz_show(struct device *kdev, struct device_attribute *attr, char *buf) @@ -229,7 +229,7 @@ static ssize_t gt_max_freq_mhz_show(struct device *kdev, struct device_attribute ret = dev_priv->rps.max_delay * GT_FREQUENCY_MULTIPLIER; mutex_unlock(&dev_priv->rps.hw_lock); - return snprintf(buf, PAGE_SIZE, "%d", ret); + return snprintf(buf, PAGE_SIZE, "%d\n", ret); } static ssize_t gt_max_freq_mhz_store(struct device *kdev, @@ -280,7 +280,7 @@ static ssize_t gt_min_freq_mhz_show(struct device *kdev, struct device_attribute ret = dev_priv->rps.min_delay * GT_FREQUENCY_MULTIPLIER; mutex_unlock(&dev_priv->rps.hw_lock); - return snprintf(buf, PAGE_SIZE, "%d", ret); + return snprintf(buf, PAGE_SIZE, "%d\n", ret); } static ssize_t gt_min_freq_mhz_store(struct device *kdev, @@ -355,7 +355,7 @@ static ssize_t gt_rp_mhz_show(struct device *kdev, struct device_attribute *attr } else { BUG(); } - return snprintf(buf, PAGE_SIZE, "%d", val); + return snprintf(buf, PAGE_SIZE, "%d\n", val); } static const struct attribute *gen6_attrs[] = { From 9ed9809fbee47cb21c5d40e0a6f46101150cc4d4 Mon Sep 17 00:00:00 2001 From: Mika Kuoppala Date: Tue, 19 Feb 2013 12:50:09 +0200 Subject: [PATCH 07/79] drm/i915: remove obsolete obj assignment in page flip Signed-off-by: Mika Kuoppala Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_display.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index ba8307dc03be..9b0cd866fb6b 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -6960,7 +6960,6 @@ static void do_intel_finish_page_flip(struct drm_device *dev, drm_i915_private_t *dev_priv = dev->dev_private; struct intel_crtc *intel_crtc = to_intel_crtc(crtc); struct intel_unpin_work *work; - struct drm_i915_gem_object *obj; unsigned long flags; /* Ignore early vblank irqs */ @@ -6990,8 +6989,6 @@ static void do_intel_finish_page_flip(struct drm_device *dev, spin_unlock_irqrestore(&dev->event_lock, flags); - obj = work->old_fb_obj; - wake_up_all(&dev_priv->pending_flip_queue); queue_work(dev_priv->wq, &work->work); From 22b8bf17c6c1db887e3e9adb0778d6f03e621e66 Mon Sep 17 00:00:00 2001 From: Paulo Zanoni Date: Mon, 18 Feb 2013 19:00:23 -0300 Subject: [PATCH 08/79] drm/i915: use HAS_DDI on intel_hdmi.c and intel_display.c Since basically every code called on these places comes from intel_ddi.c Signed-off-by: Paulo Zanoni Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_dp.c | 12 ++++++------ drivers/gpu/drm/i915/intel_hdmi.c | 2 +- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c index 7b8bfe8982e6..770ec90e37a5 100644 --- a/drivers/gpu/drm/i915/intel_dp.c +++ b/drivers/gpu/drm/i915/intel_dp.c @@ -332,7 +332,7 @@ intel_dp_aux_wait_done(struct intel_dp *intel_dp, bool has_aux_irq) uint32_t status; bool done; - if (IS_HASWELL(dev)) { + if (HAS_DDI(dev)) { switch (intel_dig_port->port) { case PORT_A: ch_ctl = DPA_AUX_CH_CTL; @@ -387,7 +387,7 @@ intel_dp_aux_ch(struct intel_dp *intel_dp, */ pm_qos_update_request(&dev_priv->pm_qos, 0); - if (IS_HASWELL(dev)) { + if (HAS_DDI(dev)) { switch (intel_dig_port->port) { case PORT_A: ch_ctl = DPA_AUX_CH_CTL; @@ -842,7 +842,7 @@ intel_dp_set_m_n(struct drm_crtc *crtc, struct drm_display_mode *mode, intel_link_compute_m_n(intel_crtc->bpp, lane_count, mode->clock, adjusted_mode->clock, &m_n); - if (IS_HASWELL(dev)) { + if (HAS_DDI(dev)) { I915_WRITE(PIPE_DATA_M1(cpu_transcoder), TU_SIZE(m_n.tu) | m_n.gmch_m); I915_WRITE(PIPE_DATA_N1(cpu_transcoder), m_n.gmch_n); @@ -1537,7 +1537,7 @@ intel_dp_pre_emphasis_max(struct intel_dp *intel_dp, uint8_t voltage_swing) { struct drm_device *dev = intel_dp_to_dev(intel_dp); - if (IS_HASWELL(dev)) { + if (HAS_DDI(dev)) { switch (voltage_swing & DP_TRAIN_VOLTAGE_SWING_MASK) { case DP_TRAIN_VOLTAGE_SWING_400: return DP_TRAIN_PRE_EMPHASIS_9_5; @@ -1745,7 +1745,7 @@ intel_dp_set_signal_levels(struct intel_dp *intel_dp, uint32_t *DP) uint32_t signal_levels, mask; uint8_t train_set = intel_dp->train_set[0]; - if (IS_HASWELL(dev)) { + if (HAS_DDI(dev)) { signal_levels = intel_hsw_signal_levels(train_set); mask = DDI_BUF_EMP_MASK; } else if (IS_GEN7(dev) && is_cpu_edp(intel_dp) && !IS_VALLEYVIEW(dev)) { @@ -1776,7 +1776,7 @@ intel_dp_set_link_train(struct intel_dp *intel_dp, int ret; uint32_t temp; - if (IS_HASWELL(dev)) { + if (HAS_DDI(dev)) { temp = I915_READ(DP_TP_CTL(port)); if (dp_train_pat & DP_LINK_SCRAMBLING_DISABLE) diff --git a/drivers/gpu/drm/i915/intel_hdmi.c b/drivers/gpu/drm/i915/intel_hdmi.c index 5a6138c62fe9..ed65c6ddf5a2 100644 --- a/drivers/gpu/drm/i915/intel_hdmi.c +++ b/drivers/gpu/drm/i915/intel_hdmi.c @@ -1044,7 +1044,7 @@ void intel_hdmi_init_connector(struct intel_digital_port *intel_dig_port, } else if (IS_VALLEYVIEW(dev)) { intel_hdmi->write_infoframe = vlv_write_infoframe; intel_hdmi->set_infoframes = vlv_set_infoframes; - } else if (IS_HASWELL(dev)) { + } else if (HAS_DDI(dev)) { intel_hdmi->write_infoframe = hsw_write_infoframe; intel_hdmi->set_infoframes = hsw_set_infoframes; } else if (HAS_PCH_IBX(dev)) { From b90f517627f76640e0f6d2aa17f143dc10623a58 Mon Sep 17 00:00:00 2001 From: Paulo Zanoni Date: Mon, 18 Feb 2013 19:00:24 -0300 Subject: [PATCH 09/79] drm/i915: wait_event_timeout's timeout is in jiffies So use msecs_to_jiffies(10) to make the timeout the same as in the "!has_aux_irq" case. This patch was initially written by Daniel Vetter and posted on pastebin a few weeks ago. I'm just bringing it to the mailing list. Signed-off-by: Paulo Zanoni Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_dp.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c index 770ec90e37a5..00bc79f03039 100644 --- a/drivers/gpu/drm/i915/intel_dp.c +++ b/drivers/gpu/drm/i915/intel_dp.c @@ -353,7 +353,8 @@ intel_dp_aux_wait_done(struct intel_dp *intel_dp, bool has_aux_irq) #define C (((status = I915_READ_NOTRACE(ch_ctl)) & DP_AUX_CH_CTL_SEND_BUSY) == 0) if (has_aux_irq) - done = wait_event_timeout(dev_priv->gmbus_wait_queue, C, 10); + done = wait_event_timeout(dev_priv->gmbus_wait_queue, C, + msecs_to_jiffies(10)); else done = wait_for_atomic(C, 10) == 0; if (!done) From 9ed35ab1dd286ed04adde8c988925f1eb149a38a Mon Sep 17 00:00:00 2001 From: Paulo Zanoni Date: Mon, 18 Feb 2013 19:00:25 -0300 Subject: [PATCH 10/79] drm/i915: add aux_ch_ctl_reg to struct intel_dp This way we can remove some duplicated code and avoid more mistakes and regressions with these registers in the future. Signed-off-by: Paulo Zanoni Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_dp.c | 66 ++++++++++---------------------- drivers/gpu/drm/i915/intel_drv.h | 1 + 2 files changed, 22 insertions(+), 45 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c index 00bc79f03039..0e2750cf85ef 100644 --- a/drivers/gpu/drm/i915/intel_dp.c +++ b/drivers/gpu/drm/i915/intel_dp.c @@ -328,29 +328,10 @@ intel_dp_aux_wait_done(struct intel_dp *intel_dp, bool has_aux_irq) struct intel_digital_port *intel_dig_port = dp_to_dig_port(intel_dp); struct drm_device *dev = intel_dig_port->base.base.dev; struct drm_i915_private *dev_priv = dev->dev_private; - uint32_t ch_ctl = intel_dp->output_reg + 0x10; + uint32_t ch_ctl = intel_dp->aux_ch_ctl_reg; uint32_t status; bool done; - if (HAS_DDI(dev)) { - switch (intel_dig_port->port) { - case PORT_A: - ch_ctl = DPA_AUX_CH_CTL; - break; - case PORT_B: - ch_ctl = PCH_DPB_AUX_CH_CTL; - break; - case PORT_C: - ch_ctl = PCH_DPC_AUX_CH_CTL; - break; - case PORT_D: - ch_ctl = PCH_DPD_AUX_CH_CTL; - break; - default: - BUG(); - } - } - #define C (((status = I915_READ_NOTRACE(ch_ctl)) & DP_AUX_CH_CTL_SEND_BUSY) == 0) if (has_aux_irq) done = wait_event_timeout(dev_priv->gmbus_wait_queue, C, @@ -370,11 +351,10 @@ intel_dp_aux_ch(struct intel_dp *intel_dp, uint8_t *send, int send_bytes, uint8_t *recv, int recv_size) { - uint32_t output_reg = intel_dp->output_reg; struct intel_digital_port *intel_dig_port = dp_to_dig_port(intel_dp); struct drm_device *dev = intel_dig_port->base.base.dev; struct drm_i915_private *dev_priv = dev->dev_private; - uint32_t ch_ctl = output_reg + 0x10; + uint32_t ch_ctl = intel_dp->aux_ch_ctl_reg; uint32_t ch_data = ch_ctl + 4; int i, ret, recv_bytes; uint32_t status; @@ -388,29 +368,6 @@ intel_dp_aux_ch(struct intel_dp *intel_dp, */ pm_qos_update_request(&dev_priv->pm_qos, 0); - if (HAS_DDI(dev)) { - switch (intel_dig_port->port) { - case PORT_A: - ch_ctl = DPA_AUX_CH_CTL; - ch_data = DPA_AUX_CH_DATA1; - break; - case PORT_B: - ch_ctl = PCH_DPB_AUX_CH_CTL; - ch_data = PCH_DPB_AUX_CH_DATA1; - break; - case PORT_C: - ch_ctl = PCH_DPC_AUX_CH_CTL; - ch_data = PCH_DPC_AUX_CH_DATA1; - break; - case PORT_D: - ch_ctl = PCH_DPD_AUX_CH_CTL; - ch_data = PCH_DPD_AUX_CH_DATA1; - break; - default: - BUG(); - } - } - intel_dp_check_edp(intel_dp); /* The clock divider is based off the hrawclk, * and would like to run at 2MHz. So, take the @@ -2832,6 +2789,25 @@ intel_dp_init_connector(struct intel_digital_port *intel_dig_port, else intel_connector->get_hw_state = intel_connector_get_hw_state; + intel_dp->aux_ch_ctl_reg = intel_dp->output_reg + 0x10; + if (HAS_DDI(dev)) { + switch (intel_dig_port->port) { + case PORT_A: + intel_dp->aux_ch_ctl_reg = DPA_AUX_CH_CTL; + break; + case PORT_B: + intel_dp->aux_ch_ctl_reg = PCH_DPB_AUX_CH_CTL; + break; + case PORT_C: + intel_dp->aux_ch_ctl_reg = PCH_DPC_AUX_CH_CTL; + break; + case PORT_D: + intel_dp->aux_ch_ctl_reg = PCH_DPD_AUX_CH_CTL; + break; + default: + BUG(); + } + } /* Set up the DDC bus. */ switch (port) { diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index febed9a010da..f21e22612bd8 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -366,6 +366,7 @@ struct intel_hdmi { struct intel_dp { uint32_t output_reg; + uint32_t aux_ch_ctl_reg; uint32_t DP; uint8_t link_configuration[DP_LINK_CONFIGURATION_SIZE]; bool has_audio; From b242b7f745650832f445dca3e19efc3dd2d65a66 Mon Sep 17 00:00:00 2001 From: Paulo Zanoni Date: Mon, 18 Feb 2013 19:00:26 -0300 Subject: [PATCH 11/79] drm/i915: rename sdvox_reg to hdmi_reg on HDMI context Some (but not all) of the HDMI registers can be used to control sDVO, so those registers have two names. IMHO, when we're talking about HDMI, we really should call the HDMI control register "hdmi_reg" instead of "sdvox_reg", otherwise we'll just confuse people reading our code (we now have platforms with HDMI but without SDVO). So now "struct intel_hdmi" has a member called "hdmi_reg" instead of "sdvox_reg". Also, don't worry: "struct intel_sdvo" still has a member called "sdvo_reg". v2: Rebase (v1 was sent in May 2012). Signed-off-by: Paulo Zanoni Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_ddi.c | 4 +- drivers/gpu/drm/i915/intel_drv.h | 4 +- drivers/gpu/drm/i915/intel_hdmi.c | 72 +++++++++++++++---------------- 3 files changed, 39 insertions(+), 41 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_ddi.c b/drivers/gpu/drm/i915/intel_ddi.c index 816c45c71b72..56bb7cb78263 100644 --- a/drivers/gpu/drm/i915/intel_ddi.c +++ b/drivers/gpu/drm/i915/intel_ddi.c @@ -1538,9 +1538,7 @@ void intel_ddi_init(struct drm_device *dev, enum port port) intel_dig_port->port_reversal = I915_READ(DDI_BUF_CTL(port)) & DDI_BUF_PORT_REVERSAL; if (hdmi_connector) - intel_dig_port->hdmi.sdvox_reg = DDI_BUF_CTL(port); - else - intel_dig_port->hdmi.sdvox_reg = 0; + intel_dig_port->hdmi.hdmi_reg = DDI_BUF_CTL(port); intel_dig_port->dp.output_reg = DDI_BUF_CTL(port); intel_encoder->type = INTEL_OUTPUT_UNKNOWN; diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index f21e22612bd8..010e998dda5f 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -347,7 +347,7 @@ struct dip_infoframe { } __attribute__((packed)); struct intel_hdmi { - u32 sdvox_reg; + u32 hdmi_reg; int ddc_bus; uint32_t color_range; bool color_range_auto; @@ -444,7 +444,7 @@ extern void intel_attach_broadcast_rgb_property(struct drm_connector *connector) extern void intel_crt_init(struct drm_device *dev); extern void intel_hdmi_init(struct drm_device *dev, - int sdvox_reg, enum port port); + int hdmi_reg, enum port port); extern void intel_hdmi_init_connector(struct intel_digital_port *intel_dig_port, struct intel_connector *intel_connector); extern struct intel_hdmi *enc_to_intel_hdmi(struct drm_encoder *encoder); diff --git a/drivers/gpu/drm/i915/intel_hdmi.c b/drivers/gpu/drm/i915/intel_hdmi.c index ed65c6ddf5a2..fcb36c6b4434 100644 --- a/drivers/gpu/drm/i915/intel_hdmi.c +++ b/drivers/gpu/drm/i915/intel_hdmi.c @@ -50,7 +50,7 @@ assert_hdmi_port_disabled(struct intel_hdmi *intel_hdmi) enabled_bits = HAS_DDI(dev) ? DDI_BUF_CTL_ENABLE : SDVO_ENABLE; - WARN(I915_READ(intel_hdmi->sdvox_reg) & enabled_bits, + WARN(I915_READ(intel_hdmi->hdmi_reg) & enabled_bits, "HDMI port enabled, expecting disabled\n"); } @@ -597,40 +597,40 @@ static void intel_hdmi_mode_set(struct drm_encoder *encoder, struct drm_i915_private *dev_priv = dev->dev_private; struct intel_crtc *intel_crtc = to_intel_crtc(encoder->crtc); struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(encoder); - u32 sdvox; + u32 hdmi_val; - sdvox = SDVO_ENCODING_HDMI; + hdmi_val = SDVO_ENCODING_HDMI; if (!HAS_PCH_SPLIT(dev)) - sdvox |= intel_hdmi->color_range; + hdmi_val |= intel_hdmi->color_range; if (adjusted_mode->flags & DRM_MODE_FLAG_PVSYNC) - sdvox |= SDVO_VSYNC_ACTIVE_HIGH; + hdmi_val |= SDVO_VSYNC_ACTIVE_HIGH; if (adjusted_mode->flags & DRM_MODE_FLAG_PHSYNC) - sdvox |= SDVO_HSYNC_ACTIVE_HIGH; + hdmi_val |= SDVO_HSYNC_ACTIVE_HIGH; if (intel_crtc->bpp > 24) - sdvox |= COLOR_FORMAT_12bpc; + hdmi_val |= COLOR_FORMAT_12bpc; else - sdvox |= COLOR_FORMAT_8bpc; + hdmi_val |= COLOR_FORMAT_8bpc; /* Required on CPT */ if (intel_hdmi->has_hdmi_sink && HAS_PCH_CPT(dev)) - sdvox |= HDMI_MODE_SELECT; + hdmi_val |= HDMI_MODE_SELECT; if (intel_hdmi->has_audio) { DRM_DEBUG_DRIVER("Enabling HDMI audio on pipe %c\n", pipe_name(intel_crtc->pipe)); - sdvox |= SDVO_AUDIO_ENABLE; - sdvox |= SDVO_NULL_PACKETS_DURING_VSYNC; + hdmi_val |= SDVO_AUDIO_ENABLE; + hdmi_val |= SDVO_NULL_PACKETS_DURING_VSYNC; intel_write_eld(encoder, adjusted_mode); } if (HAS_PCH_CPT(dev)) - sdvox |= PORT_TRANS_SEL_CPT(intel_crtc->pipe); + hdmi_val |= PORT_TRANS_SEL_CPT(intel_crtc->pipe); else if (intel_crtc->pipe == PIPE_B) - sdvox |= SDVO_PIPE_B_SELECT; + hdmi_val |= SDVO_PIPE_B_SELECT; - I915_WRITE(intel_hdmi->sdvox_reg, sdvox); - POSTING_READ(intel_hdmi->sdvox_reg); + I915_WRITE(intel_hdmi->hdmi_reg, hdmi_val); + POSTING_READ(intel_hdmi->hdmi_reg); intel_hdmi->set_infoframes(encoder, adjusted_mode); } @@ -643,7 +643,7 @@ static bool intel_hdmi_get_hw_state(struct intel_encoder *encoder, struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(&encoder->base); u32 tmp; - tmp = I915_READ(intel_hdmi->sdvox_reg); + tmp = I915_READ(intel_hdmi->hdmi_reg); if (!(tmp & SDVO_ENABLE)) return false; @@ -667,7 +667,7 @@ static void intel_enable_hdmi(struct intel_encoder *encoder) if (intel_hdmi->has_audio) enable_bits |= SDVO_AUDIO_ENABLE; - temp = I915_READ(intel_hdmi->sdvox_reg); + temp = I915_READ(intel_hdmi->hdmi_reg); /* HW workaround for IBX, we need to move the port to transcoder A * before disabling it. */ @@ -684,21 +684,21 @@ static void intel_enable_hdmi(struct intel_encoder *encoder) * we do this anyway which shows more stable in testing. */ if (HAS_PCH_SPLIT(dev)) { - I915_WRITE(intel_hdmi->sdvox_reg, temp & ~SDVO_ENABLE); - POSTING_READ(intel_hdmi->sdvox_reg); + I915_WRITE(intel_hdmi->hdmi_reg, temp & ~SDVO_ENABLE); + POSTING_READ(intel_hdmi->hdmi_reg); } temp |= enable_bits; - I915_WRITE(intel_hdmi->sdvox_reg, temp); - POSTING_READ(intel_hdmi->sdvox_reg); + I915_WRITE(intel_hdmi->hdmi_reg, temp); + POSTING_READ(intel_hdmi->hdmi_reg); /* HW workaround, need to write this twice for issue that may result * in first write getting masked. */ if (HAS_PCH_SPLIT(dev)) { - I915_WRITE(intel_hdmi->sdvox_reg, temp); - POSTING_READ(intel_hdmi->sdvox_reg); + I915_WRITE(intel_hdmi->hdmi_reg, temp); + POSTING_READ(intel_hdmi->hdmi_reg); } } @@ -710,7 +710,7 @@ static void intel_disable_hdmi(struct intel_encoder *encoder) u32 temp; u32 enable_bits = SDVO_ENABLE | SDVO_AUDIO_ENABLE; - temp = I915_READ(intel_hdmi->sdvox_reg); + temp = I915_READ(intel_hdmi->hdmi_reg); /* HW workaround for IBX, we need to move the port to transcoder A * before disabling it. */ @@ -720,12 +720,12 @@ static void intel_disable_hdmi(struct intel_encoder *encoder) if (temp & SDVO_PIPE_B_SELECT) { temp &= ~SDVO_PIPE_B_SELECT; - I915_WRITE(intel_hdmi->sdvox_reg, temp); - POSTING_READ(intel_hdmi->sdvox_reg); + I915_WRITE(intel_hdmi->hdmi_reg, temp); + POSTING_READ(intel_hdmi->hdmi_reg); /* Again we need to write this twice. */ - I915_WRITE(intel_hdmi->sdvox_reg, temp); - POSTING_READ(intel_hdmi->sdvox_reg); + I915_WRITE(intel_hdmi->hdmi_reg, temp); + POSTING_READ(intel_hdmi->hdmi_reg); /* Transcoder selection bits only update * effectively on vblank. */ @@ -740,21 +740,21 @@ static void intel_disable_hdmi(struct intel_encoder *encoder) * we do this anyway which shows more stable in testing. */ if (HAS_PCH_SPLIT(dev)) { - I915_WRITE(intel_hdmi->sdvox_reg, temp & ~SDVO_ENABLE); - POSTING_READ(intel_hdmi->sdvox_reg); + I915_WRITE(intel_hdmi->hdmi_reg, temp & ~SDVO_ENABLE); + POSTING_READ(intel_hdmi->hdmi_reg); } temp &= ~enable_bits; - I915_WRITE(intel_hdmi->sdvox_reg, temp); - POSTING_READ(intel_hdmi->sdvox_reg); + I915_WRITE(intel_hdmi->hdmi_reg, temp); + POSTING_READ(intel_hdmi->hdmi_reg); /* HW workaround, need to write this twice for issue that may result * in first write getting masked. */ if (HAS_PCH_SPLIT(dev)) { - I915_WRITE(intel_hdmi->sdvox_reg, temp); - POSTING_READ(intel_hdmi->sdvox_reg); + I915_WRITE(intel_hdmi->hdmi_reg, temp); + POSTING_READ(intel_hdmi->hdmi_reg); } } @@ -1075,7 +1075,7 @@ void intel_hdmi_init_connector(struct intel_digital_port *intel_dig_port, } } -void intel_hdmi_init(struct drm_device *dev, int sdvox_reg, enum port port) +void intel_hdmi_init(struct drm_device *dev, int hdmi_reg, enum port port) { struct intel_digital_port *intel_dig_port; struct intel_encoder *intel_encoder; @@ -1108,7 +1108,7 @@ void intel_hdmi_init(struct drm_device *dev, int sdvox_reg, enum port port) intel_encoder->cloneable = false; intel_dig_port->port = port; - intel_dig_port->hdmi.sdvox_reg = sdvox_reg; + intel_dig_port->hdmi.hdmi_reg = hdmi_reg; intel_dig_port->dp.output_reg = 0; intel_hdmi_init_connector(intel_dig_port, intel_connector); From 115bc2de52af131c2c9bb2bda1adde88c9aa8fef Mon Sep 17 00:00:00 2001 From: Paulo Zanoni Date: Mon, 18 Feb 2013 19:00:20 -0300 Subject: [PATCH 12/79] drm/i915: create functions for the "unclaimed register" checks This avoids polluting i915_write##x and also allows us to reuse code on i915_read##x. v2: Rebase v3: Convert the macros to static functions Signed-off-by: Paulo Zanoni Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_drv.c | 31 +++++++++++++++++++++++-------- 1 file changed, 23 insertions(+), 8 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_drv.c b/drivers/gpu/drm/i915/i915_drv.c index 857dd2ce30aa..07ac769d7313 100644 --- a/drivers/gpu/drm/i915/i915_drv.c +++ b/drivers/gpu/drm/i915/i915_drv.c @@ -1129,6 +1129,27 @@ ilk_dummy_write(struct drm_i915_private *dev_priv) I915_WRITE_NOTRACE(MI_MODE, 0); } +static void +hsw_unclaimed_reg_clear(struct drm_i915_private *dev_priv, u32 reg) +{ + if (IS_HASWELL(dev_priv->dev) && + (I915_READ_NOTRACE(GEN7_ERR_INT) & ERR_INT_MMIO_UNCLAIMED)) { + DRM_ERROR("Unknown unclaimed register before writing to %x\n", + reg); + I915_WRITE_NOTRACE(GEN7_ERR_INT, ERR_INT_MMIO_UNCLAIMED); + } +} + +static void +hsw_unclaimed_reg_check(struct drm_i915_private *dev_priv, u32 reg) +{ + if (IS_HASWELL(dev_priv->dev) && + (I915_READ_NOTRACE(GEN7_ERR_INT) & ERR_INT_MMIO_UNCLAIMED)) { + DRM_ERROR("Unclaimed write to %x\n", reg); + writel(ERR_INT_MMIO_UNCLAIMED, dev_priv->regs + GEN7_ERR_INT); + } +} + #define __i915_read(x, y) \ u##x i915_read##x(struct drm_i915_private *dev_priv, u32 reg) { \ u##x val = 0; \ @@ -1165,18 +1186,12 @@ void i915_write##x(struct drm_i915_private *dev_priv, u32 reg, u##x val) { \ } \ if (IS_GEN5(dev_priv->dev)) \ ilk_dummy_write(dev_priv); \ - if (IS_HASWELL(dev_priv->dev) && (I915_READ_NOTRACE(GEN7_ERR_INT) & ERR_INT_MMIO_UNCLAIMED)) { \ - DRM_ERROR("Unknown unclaimed register before writing to %x\n", reg); \ - I915_WRITE_NOTRACE(GEN7_ERR_INT, ERR_INT_MMIO_UNCLAIMED); \ - } \ + hsw_unclaimed_reg_clear(dev_priv, reg); \ write##y(val, dev_priv->regs + reg); \ if (unlikely(__fifo_ret)) { \ gen6_gt_check_fifodbg(dev_priv); \ } \ - if (IS_HASWELL(dev_priv->dev) && (I915_READ_NOTRACE(GEN7_ERR_INT) & ERR_INT_MMIO_UNCLAIMED)) { \ - DRM_ERROR("Unclaimed write to %x\n", reg); \ - writel(ERR_INT_MMIO_UNCLAIMED, dev_priv->regs + GEN7_ERR_INT); \ - } \ + hsw_unclaimed_reg_check(dev_priv, reg); \ } __i915_write(8, b) __i915_write(16, w) From 3f1e109a8be5670487e00e1c6bc0670526325227 Mon Sep 17 00:00:00 2001 From: Paulo Zanoni Date: Mon, 18 Feb 2013 19:00:21 -0300 Subject: [PATCH 13/79] drm/i915: use FPGA_DBG for the "unclaimed register" checks We plan to treat GEN7_ERR_INT as an interrupt, so use this register for the checks inside I915_WRITE. This way we can have the best of both worlds: the error message with a register address and the V2: Split in 2 patches: one for the macro, one for changing the register, as requested by Ben. V3: Rebase. Signed-off-by: Paulo Zanoni Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_drv.c | 8 ++++---- drivers/gpu/drm/i915/i915_reg.h | 3 +++ 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_drv.c b/drivers/gpu/drm/i915/i915_drv.c index 07ac769d7313..b342749fcc87 100644 --- a/drivers/gpu/drm/i915/i915_drv.c +++ b/drivers/gpu/drm/i915/i915_drv.c @@ -1133,10 +1133,10 @@ static void hsw_unclaimed_reg_clear(struct drm_i915_private *dev_priv, u32 reg) { if (IS_HASWELL(dev_priv->dev) && - (I915_READ_NOTRACE(GEN7_ERR_INT) & ERR_INT_MMIO_UNCLAIMED)) { + (I915_READ_NOTRACE(FPGA_DBG) & FPGA_DBG_RM_NOCLAIM)) { DRM_ERROR("Unknown unclaimed register before writing to %x\n", reg); - I915_WRITE_NOTRACE(GEN7_ERR_INT, ERR_INT_MMIO_UNCLAIMED); + I915_WRITE_NOTRACE(FPGA_DBG, FPGA_DBG_RM_NOCLAIM); } } @@ -1144,9 +1144,9 @@ static void hsw_unclaimed_reg_check(struct drm_i915_private *dev_priv, u32 reg) { if (IS_HASWELL(dev_priv->dev) && - (I915_READ_NOTRACE(GEN7_ERR_INT) & ERR_INT_MMIO_UNCLAIMED)) { + (I915_READ_NOTRACE(FPGA_DBG) & FPGA_DBG_RM_NOCLAIM)) { DRM_ERROR("Unclaimed write to %x\n", reg); - writel(ERR_INT_MMIO_UNCLAIMED, dev_priv->regs + GEN7_ERR_INT); + I915_WRITE_NOTRACE(FPGA_DBG, FPGA_DBG_RM_NOCLAIM); } } diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index 527b664d3434..9e5844b2f1f5 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -522,6 +522,9 @@ #define GEN7_ERR_INT 0x44040 #define ERR_INT_MMIO_UNCLAIMED (1<<13) +#define FPGA_DBG 0x42300 +#define FPGA_DBG_RM_NOCLAIM (1<<31) + #define DERRMR 0x44050 /* GM45+ chicken bits -- debug workaround bits that may be required From 02bcca0d72a1491d30cfb5dce29e348ac15fd01c Mon Sep 17 00:00:00 2001 From: Paulo Zanoni Date: Tue, 19 Feb 2013 16:13:35 -0300 Subject: [PATCH 14/79] drm/i915: clear the FPGA_DBG_RM_NOCLAIM bit at driver init Otherwise, if the BIOS did anything wrong, our first I915_{WRITE,READ} will give us "unclaimed register" messages. V2: Even earlier. V3: Move it to intel_early_sanitize_regs. Bugzilla: http://bugs.freedesktop.org/show_bug.cgi?id=58897 Signed-off-by: Paulo Zanoni Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_dma.c | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/drivers/gpu/drm/i915/i915_dma.c b/drivers/gpu/drm/i915/i915_dma.c index 4fa6beb14c77..e16099b6f942 100644 --- a/drivers/gpu/drm/i915/i915_dma.c +++ b/drivers/gpu/drm/i915/i915_dma.c @@ -1452,6 +1452,22 @@ static void i915_dump_device_info(struct drm_i915_private *dev_priv) #undef DEV_INFO_SEP } +/** + * intel_early_sanitize_regs - clean up BIOS state + * @dev: DRM device + * + * This function must be called before we do any I915_READ or I915_WRITE. Its + * purpose is to clean up any state left by the BIOS that may affect us when + * reading and/or writing registers. + */ +static void intel_early_sanitize_regs(struct drm_device *dev) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + + if (IS_HASWELL(dev)) + I915_WRITE_NOTRACE(FPGA_DBG, FPGA_DBG_RM_NOCLAIM); +} + /** * i915_driver_load - setup chip and create an initial config * @dev: DRM device @@ -1542,6 +1558,8 @@ int i915_driver_load(struct drm_device *dev, unsigned long flags) goto put_gmch; } + intel_early_sanitize_regs(dev); + aperture_size = dev_priv->gtt.mappable_end; dev_priv->gtt.mappable = From 2ec90668e3db1d9fe9bb8370d74a5e51709c2d79 Mon Sep 17 00:00:00 2001 From: Jesse Barnes Date: Tue, 19 Feb 2013 12:11:38 -0800 Subject: [PATCH 15/79] drm/i915: don't restore LVDS enable state blindly v2 We still rely on a few LVDS bits, but restoring the enable bit can cause trouble at this point, so don't. v2: use the right mask to prevent restore (Daniel) conditionalize on KMS support (Denial) Signed-off-by: Jesse Barnes Reviewed-by: Paulo Zanoni Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_suspend.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_suspend.c b/drivers/gpu/drm/i915/i915_suspend.c index 2135f21ea458..c1e02b040a34 100644 --- a/drivers/gpu/drm/i915/i915_suspend.c +++ b/drivers/gpu/drm/i915/i915_suspend.c @@ -255,6 +255,7 @@ static void i915_save_display(struct drm_device *dev) static void i915_restore_display(struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; + u32 mask = 0xffffffff; /* Display arbitration */ if (INTEL_INFO(dev)->gen <= 4) @@ -267,10 +268,13 @@ static void i915_restore_display(struct drm_device *dev) if (INTEL_INFO(dev)->gen >= 4 && !HAS_PCH_SPLIT(dev)) I915_WRITE(BLC_PWM_CTL2, dev_priv->regfile.saveBLC_PWM_CTL2); + if (drm_core_check_feature(dev, DRIVER_MODESET)) + mask = ~LVDS_PORT_EN; + if (HAS_PCH_SPLIT(dev)) { - I915_WRITE(PCH_LVDS, dev_priv->regfile.saveLVDS); + I915_WRITE(PCH_LVDS, dev_priv->regfile.saveLVDS & mask); } else if (IS_MOBILE(dev) && !IS_I830(dev)) - I915_WRITE(LVDS, dev_priv->regfile.saveLVDS); + I915_WRITE(LVDS, dev_priv->regfile.saveLVDS & mask); if (!IS_I830(dev) && !IS_845G(dev) && !HAS_PCH_SPLIT(dev)) I915_WRITE(PFIT_CONTROL, dev_priv->regfile.savePFIT_CONTROL); From 5e2032d47ac9b67e671bd855c5e68005190954da Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Tue, 19 Feb 2013 15:16:38 +0200 Subject: [PATCH 16/79] drm/i915: Eliminate race from gen2/3 page flip interrupt handling MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit If the interrupt handler were to process a previous vblank interrupt and the following flip pending interrupt at the same time, the page flip would be completed too soon. To eliminate this race, check the live pending flip status from the ISR register before finishing the page flip. v2: Added a comment explaining the logic (by Chris Wilson) v3: Fix a typo in the comment Reviewed-by: Chris Wilson Tested-by: Chris Wilson Signed-off-by: Ville Syrjälä Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_irq.c | 27 +++++++++++++++++++++------ 1 file changed, 21 insertions(+), 6 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c index 9fde49a29999..6488249477db 100644 --- a/drivers/gpu/drm/i915/i915_irq.c +++ b/drivers/gpu/drm/i915/i915_irq.c @@ -2284,8 +2284,11 @@ static irqreturn_t i8xx_irq_handler(int irq, void *arg) drm_handle_vblank(dev, 0)) { if (iir & I915_DISPLAY_PLANE_A_FLIP_PENDING_INTERRUPT) { intel_prepare_page_flip(dev, 0); - intel_finish_page_flip(dev, 0); - flip_mask &= ~I915_DISPLAY_PLANE_A_FLIP_PENDING_INTERRUPT; + + if ((I915_READ16(ISR) & I915_DISPLAY_PLANE_A_FLIP_PENDING_INTERRUPT) == 0) { + intel_finish_page_flip(dev, 0); + flip_mask &= ~I915_DISPLAY_PLANE_A_FLIP_PENDING_INTERRUPT; + } } } @@ -2293,8 +2296,11 @@ static irqreturn_t i8xx_irq_handler(int irq, void *arg) drm_handle_vblank(dev, 1)) { if (iir & I915_DISPLAY_PLANE_B_FLIP_PENDING_INTERRUPT) { intel_prepare_page_flip(dev, 1); - intel_finish_page_flip(dev, 1); - flip_mask &= ~I915_DISPLAY_PLANE_B_FLIP_PENDING_INTERRUPT; + + if ((I915_READ16(ISR) & I915_DISPLAY_PLANE_B_FLIP_PENDING_INTERRUPT) == 0) { + intel_finish_page_flip(dev, 1); + flip_mask &= ~I915_DISPLAY_PLANE_B_FLIP_PENDING_INTERRUPT; + } } } @@ -2491,8 +2497,17 @@ static irqreturn_t i915_irq_handler(int irq, void *arg) drm_handle_vblank(dev, pipe)) { if (iir & flip[plane]) { intel_prepare_page_flip(dev, plane); - intel_finish_page_flip(dev, pipe); - flip_mask &= ~flip[plane]; + + /* We detect FlipDone by looking for the change in PendingFlip from '1' + * to '0' on the following vblank, i.e. IIR has the Pendingflip + * asserted following the MI_DISPLAY_FLIP, but ISR is deasserted, hence + * the flip is completed (no longer pending). Since this doesn't raise an + * interrupt per se, we watch for the change at vblank. + */ + if ((I915_READ(ISR) & flip[plane]) == 0) { + intel_finish_page_flip(dev, pipe); + flip_mask &= ~flip[plane]; + } } } From 21ad833075801a7cd81b5ef1604ffc6c600e5ff9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Tue, 19 Feb 2013 15:16:39 +0200 Subject: [PATCH 17/79] drm/i915: Fix races in gen4 page flip interrupt handling MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Use the gen3 logic for handling page flip interrupts on gen4. Unfortuantely this kills the stall_check since that looks like it can easily trigger too early. With the current logic the stall check would kick in on the first vblank after the flip has been submitted to the ring. If the CS takes longer than that to process the commands in the ring, the stall check will cause the page flip to be complete too early. That doesn't sound like a very good idea. Something better should be deviced if we still need the stall check. For now, mark i915_pageflip_stall_check() as unused. v2: Fix irq enable_mask and add __always_unused (Chris Wilson) References: https://bugs.launchpad.net/ubuntu/+source/xserver-xorg-video-intel/+bug/1116587 Reviewed-by: Chris Wilson Tested-by: Chris Wilson Signed-off-by: Ville Syrjälä Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_irq.c | 31 ++++++++++++++++++++----------- 1 file changed, 20 insertions(+), 11 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c index 6488249477db..18de788f1aa8 100644 --- a/drivers/gpu/drm/i915/i915_irq.c +++ b/drivers/gpu/drm/i915/i915_irq.c @@ -1547,7 +1547,7 @@ void i915_handle_error(struct drm_device *dev, bool wedged) queue_work(dev_priv->wq, &dev_priv->gpu_error.work); } -static void i915_pageflip_stall_check(struct drm_device *dev, int pipe) +static void __always_unused i915_pageflip_stall_check(struct drm_device *dev, int pipe) { drm_i915_private_t *dev_priv = dev->dev_private; struct drm_crtc *crtc = dev_priv->pipe_to_crtc_mapping[pipe]; @@ -2598,6 +2598,8 @@ static int i965_irq_postinstall(struct drm_device *dev) I915_RENDER_COMMAND_PARSER_ERROR_INTERRUPT); enable_mask = ~dev_priv->irq_mask; + enable_mask &= ~(I915_DISPLAY_PLANE_A_FLIP_PENDING_INTERRUPT | + I915_DISPLAY_PLANE_B_FLIP_PENDING_INTERRUPT); enable_mask |= I915_USER_INTERRUPT; if (IS_G4X(dev)) @@ -2684,6 +2686,13 @@ static irqreturn_t i965_irq_handler(int irq, void *arg) unsigned long irqflags; int irq_received; int ret = IRQ_NONE, pipe; + u32 flip[2] = { + I915_DISPLAY_PLANE_A_FLIP_PENDING_INTERRUPT, + I915_DISPLAY_PLANE_B_FLIP_PENDING_INTERRUPT + }; + u32 flip_mask = + I915_DISPLAY_PLANE_A_FLIP_PENDING_INTERRUPT | + I915_DISPLAY_PLANE_B_FLIP_PENDING_INTERRUPT; atomic_inc(&dev_priv->irq_received); @@ -2692,7 +2701,7 @@ static irqreturn_t i965_irq_handler(int irq, void *arg) for (;;) { bool blc_event = false; - irq_received = iir != 0; + irq_received = (iir & ~flip_mask) != 0; /* Can't rely on pipestat interrupt bit in iir as it might * have been cleared after the pipestat interrupt was received. @@ -2739,7 +2748,7 @@ static irqreturn_t i965_irq_handler(int irq, void *arg) I915_READ(PORT_HOTPLUG_STAT); } - I915_WRITE(IIR, iir); + I915_WRITE(IIR, iir & ~flip_mask); new_iir = I915_READ(IIR); /* Flush posted writes */ if (iir & I915_USER_INTERRUPT) @@ -2747,17 +2756,17 @@ static irqreturn_t i965_irq_handler(int irq, void *arg) if (iir & I915_BSD_USER_INTERRUPT) notify_ring(dev, &dev_priv->ring[VCS]); - if (iir & I915_DISPLAY_PLANE_A_FLIP_PENDING_INTERRUPT) - intel_prepare_page_flip(dev, 0); - - if (iir & I915_DISPLAY_PLANE_B_FLIP_PENDING_INTERRUPT) - intel_prepare_page_flip(dev, 1); - for_each_pipe(pipe) { if (pipe_stats[pipe] & PIPE_START_VBLANK_INTERRUPT_STATUS && drm_handle_vblank(dev, pipe)) { - i915_pageflip_stall_check(dev, pipe); - intel_finish_page_flip(dev, pipe); + if (iir & flip[pipe]) { + intel_prepare_page_flip(dev, pipe); + + if ((I915_READ(ISR) & flip[pipe]) == 0) { + intel_finish_page_flip(dev, pipe); + flip_mask &= ~flip[pipe]; + } + } } if (pipe_stats[pipe] & PIPE_LEGACY_BLC_EVENT_STATUS) From 90a72f8774b6060975f85687e9c8a60cfb68a72c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Tue, 19 Feb 2013 23:16:44 +0200 Subject: [PATCH 18/79] drm/i915: Refactor gen2 to gen4 vblank interrupt handling MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The indentation is getting way too deep. Pull the vblank interupt handling out to separate functions. v2: Keep flip_mask handling in the main irq handler and flatten {i8xx,i915}_handle_vblank() even further. Signed-off-by: Ville Syrjälä Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_irq.c | 125 ++++++++++++++++++-------------- drivers/gpu/drm/i915/i915_reg.h | 1 + 2 files changed, 72 insertions(+), 54 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c index 18de788f1aa8..29037e0e38b0 100644 --- a/drivers/gpu/drm/i915/i915_irq.c +++ b/drivers/gpu/drm/i915/i915_irq.c @@ -2226,6 +2226,37 @@ static int i8xx_irq_postinstall(struct drm_device *dev) return 0; } +/* + * Returns true when a page flip has completed. + */ +static bool i8xx_handle_vblank(struct drm_device *dev, + int pipe, u16 iir) +{ + drm_i915_private_t *dev_priv = dev->dev_private; + u16 flip_pending = DISPLAY_PLANE_FLIP_PENDING(pipe); + + if (!drm_handle_vblank(dev, pipe)) + return false; + + if ((iir & flip_pending) == 0) + return false; + + intel_prepare_page_flip(dev, pipe); + + /* We detect FlipDone by looking for the change in PendingFlip from '1' + * to '0' on the following vblank, i.e. IIR has the Pendingflip + * asserted following the MI_DISPLAY_FLIP, but ISR is deasserted, hence + * the flip is completed (no longer pending). Since this doesn't raise + * an interrupt per se, we watch for the change at vblank. + */ + if (I915_READ16(ISR) & flip_pending) + return false; + + intel_finish_page_flip(dev, pipe); + + return true; +} + static irqreturn_t i8xx_irq_handler(int irq, void *arg) { struct drm_device *dev = (struct drm_device *) arg; @@ -2281,28 +2312,12 @@ static irqreturn_t i8xx_irq_handler(int irq, void *arg) notify_ring(dev, &dev_priv->ring[RCS]); if (pipe_stats[0] & PIPE_VBLANK_INTERRUPT_STATUS && - drm_handle_vblank(dev, 0)) { - if (iir & I915_DISPLAY_PLANE_A_FLIP_PENDING_INTERRUPT) { - intel_prepare_page_flip(dev, 0); - - if ((I915_READ16(ISR) & I915_DISPLAY_PLANE_A_FLIP_PENDING_INTERRUPT) == 0) { - intel_finish_page_flip(dev, 0); - flip_mask &= ~I915_DISPLAY_PLANE_A_FLIP_PENDING_INTERRUPT; - } - } - } + i8xx_handle_vblank(dev, 0, iir)) + flip_mask &= ~DISPLAY_PLANE_FLIP_PENDING(0); if (pipe_stats[1] & PIPE_VBLANK_INTERRUPT_STATUS && - drm_handle_vblank(dev, 1)) { - if (iir & I915_DISPLAY_PLANE_B_FLIP_PENDING_INTERRUPT) { - intel_prepare_page_flip(dev, 1); - - if ((I915_READ16(ISR) & I915_DISPLAY_PLANE_B_FLIP_PENDING_INTERRUPT) == 0) { - intel_finish_page_flip(dev, 1); - flip_mask &= ~I915_DISPLAY_PLANE_B_FLIP_PENDING_INTERRUPT; - } - } - } + i8xx_handle_vblank(dev, 1, iir)) + flip_mask &= ~DISPLAY_PLANE_FLIP_PENDING(1); iir = new_iir; } @@ -2419,6 +2434,37 @@ static void i915_hpd_irq_setup(struct drm_device *dev) } } +/* + * Returns true when a page flip has completed. + */ +static bool i915_handle_vblank(struct drm_device *dev, + int plane, int pipe, u32 iir) +{ + drm_i915_private_t *dev_priv = dev->dev_private; + u32 flip_pending = DISPLAY_PLANE_FLIP_PENDING(plane); + + if (!drm_handle_vblank(dev, pipe)) + return false; + + if ((iir & flip_pending) == 0) + return false; + + intel_prepare_page_flip(dev, plane); + + /* We detect FlipDone by looking for the change in PendingFlip from '1' + * to '0' on the following vblank, i.e. IIR has the Pendingflip + * asserted following the MI_DISPLAY_FLIP, but ISR is deasserted, hence + * the flip is completed (no longer pending). Since this doesn't raise + * an interrupt per se, we watch for the change at vblank. + */ + if (I915_READ(ISR) & flip_pending) + return false; + + intel_finish_page_flip(dev, pipe); + + return true; +} + static irqreturn_t i915_irq_handler(int irq, void *arg) { struct drm_device *dev = (struct drm_device *) arg; @@ -2428,10 +2474,6 @@ static irqreturn_t i915_irq_handler(int irq, void *arg) u32 flip_mask = I915_DISPLAY_PLANE_A_FLIP_PENDING_INTERRUPT | I915_DISPLAY_PLANE_B_FLIP_PENDING_INTERRUPT; - u32 flip[2] = { - I915_DISPLAY_PLANE_A_FLIP_PENDING_INTERRUPT, - I915_DISPLAY_PLANE_B_FLIP_PENDING_INTERRUPT - }; int pipe, ret = IRQ_NONE; atomic_inc(&dev_priv->irq_received); @@ -2493,23 +2535,10 @@ static irqreturn_t i915_irq_handler(int irq, void *arg) int plane = pipe; if (IS_MOBILE(dev)) plane = !plane; - if (pipe_stats[pipe] & PIPE_VBLANK_INTERRUPT_STATUS && - drm_handle_vblank(dev, pipe)) { - if (iir & flip[plane]) { - intel_prepare_page_flip(dev, plane); - /* We detect FlipDone by looking for the change in PendingFlip from '1' - * to '0' on the following vblank, i.e. IIR has the Pendingflip - * asserted following the MI_DISPLAY_FLIP, but ISR is deasserted, hence - * the flip is completed (no longer pending). Since this doesn't raise an - * interrupt per se, we watch for the change at vblank. - */ - if ((I915_READ(ISR) & flip[plane]) == 0) { - intel_finish_page_flip(dev, pipe); - flip_mask &= ~flip[plane]; - } - } - } + if (pipe_stats[pipe] & PIPE_VBLANK_INTERRUPT_STATUS && + i915_handle_vblank(dev, plane, pipe, iir)) + flip_mask &= ~DISPLAY_PLANE_FLIP_PENDING(plane); if (pipe_stats[pipe] & PIPE_LEGACY_BLC_EVENT_STATUS) blc_event = true; @@ -2686,10 +2715,6 @@ static irqreturn_t i965_irq_handler(int irq, void *arg) unsigned long irqflags; int irq_received; int ret = IRQ_NONE, pipe; - u32 flip[2] = { - I915_DISPLAY_PLANE_A_FLIP_PENDING_INTERRUPT, - I915_DISPLAY_PLANE_B_FLIP_PENDING_INTERRUPT - }; u32 flip_mask = I915_DISPLAY_PLANE_A_FLIP_PENDING_INTERRUPT | I915_DISPLAY_PLANE_B_FLIP_PENDING_INTERRUPT; @@ -2758,16 +2783,8 @@ static irqreturn_t i965_irq_handler(int irq, void *arg) for_each_pipe(pipe) { if (pipe_stats[pipe] & PIPE_START_VBLANK_INTERRUPT_STATUS && - drm_handle_vblank(dev, pipe)) { - if (iir & flip[pipe]) { - intel_prepare_page_flip(dev, pipe); - - if ((I915_READ(ISR) & flip[pipe]) == 0) { - intel_finish_page_flip(dev, pipe); - flip_mask &= ~flip[pipe]; - } - } - } + i915_handle_vblank(dev, pipe, pipe, iir)) + flip_mask &= ~DISPLAY_PLANE_FLIP_PENDING(pipe); if (pipe_stats[pipe] & PIPE_LEGACY_BLC_EVENT_STATUS) blc_event = true; diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index 9e5844b2f1f5..cd226c21e156 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -594,6 +594,7 @@ #define I915_USER_INTERRUPT (1<<1) #define I915_ASLE_INTERRUPT (1<<0) #define I915_BSD_USER_INTERRUPT (1<<25) +#define DISPLAY_PLANE_FLIP_PENDING(plane) (1<<(11-(plane))) /* A and B only */ #define EIR 0x020b0 #define EMR 0x020b4 #define ESR 0x020b8 From 46c06a30dfd63b1200dda2337c145e262798b9cf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Wed, 20 Feb 2013 21:16:18 +0200 Subject: [PATCH 19/79] drm/i915: Kill pipestat[] cache MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Caching the PIPESTAT enable bits has been deemed pointless. Just read them from the register itself. Signed-off-by: Ville Syrjälä Reviewed-by: Jani Nikula Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_drv.h | 1 - drivers/gpu/drm/i915/i915_irq.c | 41 ++++++++++++++------------------- 2 files changed, 17 insertions(+), 25 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index e95337c97459..62b15f817792 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -905,7 +905,6 @@ typedef struct drm_i915_private { struct mutex dpio_lock; /** Cached value of IMR to avoid reads in updating the bitfield */ - u32 pipestat[2]; u32 irq_mask; u32 gt_irq_mask; diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c index 29037e0e38b0..4cbbbd688935 100644 --- a/drivers/gpu/drm/i915/i915_irq.c +++ b/drivers/gpu/drm/i915/i915_irq.c @@ -60,26 +60,30 @@ ironlake_disable_display_irq(drm_i915_private_t *dev_priv, u32 mask) void i915_enable_pipestat(drm_i915_private_t *dev_priv, int pipe, u32 mask) { - if ((dev_priv->pipestat[pipe] & mask) != mask) { - u32 reg = PIPESTAT(pipe); + u32 reg = PIPESTAT(pipe); + u32 pipestat = I915_READ(reg) & 0x7fff0000; - dev_priv->pipestat[pipe] |= mask; - /* Enable the interrupt, clear any pending status */ - I915_WRITE(reg, dev_priv->pipestat[pipe] | (mask >> 16)); - POSTING_READ(reg); - } + if ((pipestat & mask) == mask) + return; + + /* Enable the interrupt, clear any pending status */ + pipestat |= mask | (mask >> 16); + I915_WRITE(reg, pipestat); + POSTING_READ(reg); } void i915_disable_pipestat(drm_i915_private_t *dev_priv, int pipe, u32 mask) { - if ((dev_priv->pipestat[pipe] & mask) != 0) { - u32 reg = PIPESTAT(pipe); + u32 reg = PIPESTAT(pipe); + u32 pipestat = I915_READ(reg) & 0x7fff0000; - dev_priv->pipestat[pipe] &= ~mask; - I915_WRITE(reg, dev_priv->pipestat[pipe]); - POSTING_READ(reg); - } + if ((pipestat & mask) == 0) + return; + + pipestat &= ~mask; + I915_WRITE(reg, pipestat); + POSTING_READ(reg); } /** @@ -2069,9 +2073,6 @@ static int valleyview_irq_postinstall(struct drm_device *dev) I915_DISPLAY_PIPE_A_VBLANK_INTERRUPT | I915_DISPLAY_PIPE_B_VBLANK_INTERRUPT; - dev_priv->pipestat[0] = 0; - dev_priv->pipestat[1] = 0; - /* Hack for broken MSIs on VLV */ pci_write_config_dword(dev_priv->dev->pdev, 0x94, 0xfee00000); pci_read_config_word(dev->pdev, 0x98, &msid); @@ -2201,9 +2202,6 @@ static int i8xx_irq_postinstall(struct drm_device *dev) { drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; - dev_priv->pipestat[0] = 0; - dev_priv->pipestat[1] = 0; - I915_WRITE16(EMR, ~(I915_ERROR_PAGE_TABLE | I915_ERROR_MEMORY_REFRESH)); @@ -2365,9 +2363,6 @@ static int i915_irq_postinstall(struct drm_device *dev) drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; u32 enable_mask; - dev_priv->pipestat[0] = 0; - dev_priv->pipestat[1] = 0; - I915_WRITE(EMR, ~(I915_ERROR_PAGE_TABLE | I915_ERROR_MEMORY_REFRESH)); /* Unmask the interrupts that we always want on. */ @@ -2634,8 +2629,6 @@ static int i965_irq_postinstall(struct drm_device *dev) if (IS_G4X(dev)) enable_mask |= I915_BSD_USER_INTERRUPT; - dev_priv->pipestat[0] = 0; - dev_priv->pipestat[1] = 0; i915_enable_pipestat(dev_priv, 0, PIPE_GMBUS_EVENT_ENABLE); /* From 7d9bcebe13397f6621a44b998860ae0c8049b10c Mon Sep 17 00:00:00 2001 From: Rodrigo Vivi Date: Mon, 25 Feb 2013 19:55:16 -0300 Subject: [PATCH 20/79] drm/i915: Use cpu_transcoder for HSW_TVIDEO_DIP_* instead of pipe While old platforms had 3 transcoders and 3 pipes (1:1), HSW has 4 transcoders and 3 pipes. These regs were being used only by HDMI code where pipe is always the same thing as cpu_transcoder. This patch allow us to use them for DP, specially for TRANSCODER_EDP. v2: Adding HSW_TVIDEO_DIP_VSC_DATA to transmit vsc to eDP. Signed-off-by: Rodrigo Vivi Reviewed-by: Paulo Zanoni Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_reg.h | 18 ++++++++++-------- drivers/gpu/drm/i915/intel_hdmi.c | 13 +++++++------ 2 files changed, 17 insertions(+), 14 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index cd226c21e156..c6d482fdf89b 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -3758,14 +3758,16 @@ #define HSW_VIDEO_DIP_VSC_ECC_B 0x61344 #define HSW_VIDEO_DIP_GCP_B 0x61210 -#define HSW_TVIDEO_DIP_CTL(pipe) \ - _PIPE(pipe, HSW_VIDEO_DIP_CTL_A, HSW_VIDEO_DIP_CTL_B) -#define HSW_TVIDEO_DIP_AVI_DATA(pipe) \ - _PIPE(pipe, HSW_VIDEO_DIP_AVI_DATA_A, HSW_VIDEO_DIP_AVI_DATA_B) -#define HSW_TVIDEO_DIP_SPD_DATA(pipe) \ - _PIPE(pipe, HSW_VIDEO_DIP_SPD_DATA_A, HSW_VIDEO_DIP_SPD_DATA_B) -#define HSW_TVIDEO_DIP_GCP(pipe) \ - _PIPE(pipe, HSW_VIDEO_DIP_GCP_A, HSW_VIDEO_DIP_GCP_B) +#define HSW_TVIDEO_DIP_CTL(trans) \ + _TRANSCODER(trans, HSW_VIDEO_DIP_CTL_A, HSW_VIDEO_DIP_CTL_B) +#define HSW_TVIDEO_DIP_AVI_DATA(trans) \ + _TRANSCODER(trans, HSW_VIDEO_DIP_AVI_DATA_A, HSW_VIDEO_DIP_AVI_DATA_B) +#define HSW_TVIDEO_DIP_SPD_DATA(trans) \ + _TRANSCODER(trans, HSW_VIDEO_DIP_SPD_DATA_A, HSW_VIDEO_DIP_SPD_DATA_B) +#define HSW_TVIDEO_DIP_GCP(trans) \ + _TRANSCODER(trans, HSW_VIDEO_DIP_GCP_A, HSW_VIDEO_DIP_GCP_B) +#define HSW_TVIDEO_DIP_VSC_DATA(trans) \ + _TRANSCODER(trans, HSW_VIDEO_DIP_VSC_DATA_A, HSW_VIDEO_DIP_VSC_DATA_B) #define _TRANS_HTOTAL_B 0xe1000 #define _TRANS_HBLANK_B 0xe1004 diff --git a/drivers/gpu/drm/i915/intel_hdmi.c b/drivers/gpu/drm/i915/intel_hdmi.c index fcb36c6b4434..6046db0e9f8a 100644 --- a/drivers/gpu/drm/i915/intel_hdmi.c +++ b/drivers/gpu/drm/i915/intel_hdmi.c @@ -120,13 +120,14 @@ static u32 hsw_infoframe_enable(struct dip_infoframe *frame) } } -static u32 hsw_infoframe_data_reg(struct dip_infoframe *frame, enum pipe pipe) +static u32 hsw_infoframe_data_reg(struct dip_infoframe *frame, + enum transcoder cpu_transcoder) { switch (frame->type) { case DIP_TYPE_AVI: - return HSW_TVIDEO_DIP_AVI_DATA(pipe); + return HSW_TVIDEO_DIP_AVI_DATA(cpu_transcoder); case DIP_TYPE_SPD: - return HSW_TVIDEO_DIP_SPD_DATA(pipe); + return HSW_TVIDEO_DIP_SPD_DATA(cpu_transcoder); default: DRM_DEBUG_DRIVER("unknown info frame type %d\n", frame->type); return 0; @@ -293,8 +294,8 @@ static void hsw_write_infoframe(struct drm_encoder *encoder, struct drm_device *dev = encoder->dev; struct drm_i915_private *dev_priv = dev->dev_private; struct intel_crtc *intel_crtc = to_intel_crtc(encoder->crtc); - u32 ctl_reg = HSW_TVIDEO_DIP_CTL(intel_crtc->pipe); - u32 data_reg = hsw_infoframe_data_reg(frame, intel_crtc->pipe); + u32 ctl_reg = HSW_TVIDEO_DIP_CTL(intel_crtc->cpu_transcoder); + u32 data_reg = hsw_infoframe_data_reg(frame, intel_crtc->cpu_transcoder); unsigned int i, len = DIP_HEADER_SIZE + frame->len; u32 val = I915_READ(ctl_reg); @@ -568,7 +569,7 @@ static void hsw_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); - u32 reg = HSW_TVIDEO_DIP_CTL(intel_crtc->pipe); + u32 reg = HSW_TVIDEO_DIP_CTL(intel_crtc->cpu_transcoder); u32 val = I915_READ(reg); assert_hdmi_port_disabled(intel_hdmi); From 83f377abed03e46eb3b6ce14a91291e7cdf86647 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Fri, 22 Feb 2013 00:53:05 +0100 Subject: [PATCH 21/79] drm/i915: gen2 has no tv out support So ditch that if clause from the i8xx pll update code. Reviewed-by: Paulo Zanoni Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_display.c | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 9b0cd866fb6b..878e1e3e0667 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -4518,11 +4518,7 @@ static void i8xx_update_pll(struct drm_crtc *crtc, dpll |= PLL_P2_DIVIDE_BY_4; } - if (intel_pipe_has_type(crtc, INTEL_OUTPUT_TVOUT)) - /* XXX: just matching BIOS for now */ - /* dpll |= PLL_REF_INPUT_TVCLKINBC; */ - dpll |= 3; - else if (intel_pipe_has_type(crtc, INTEL_OUTPUT_LVDS) && + if (intel_pipe_has_type(crtc, INTEL_OUTPUT_LVDS) && intel_panel_use_ssc(dev_priv) && num_connectors < 2) dpll |= PLLB_REF_INPUT_SPREADSPECTRUMIN; else From 2bb4629add2e648f1822872cce72f0fe163ce605 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Fri, 22 Feb 2013 16:12:51 +0200 Subject: [PATCH 22/79] drm/i915: Add to_user_ptr() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit to_user_ptr() simply casts a pointer passed as u64 from user space to void __user * correctly. Using this lets us get rid of all the tiresome casts. The idea came from Chris Wilson . Signed-off-by: Ville Syrjälä Reviewed-by: Chris Wilson Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_drv.h | 5 +++++ drivers/gpu/drm/i915/i915_gem.c | 14 +++++++------- drivers/gpu/drm/i915/i915_gem_execbuffer.c | 20 +++++++++----------- 3 files changed, 21 insertions(+), 18 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 62b15f817792..669a535e82f3 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -1899,4 +1899,9 @@ static inline uint32_t i915_vgacntrl_reg(struct drm_device *dev) return VGACNTRL; } +static inline void __user *to_user_ptr(u64 address) +{ + return (void __user *)(uintptr_t)address; +} + #endif diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index 8413ffced815..1417fc6c28ee 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -414,7 +414,7 @@ i915_gem_shmem_pread(struct drm_device *dev, struct scatterlist *sg; int i; - user_data = (char __user *) (uintptr_t) args->data_ptr; + user_data = to_user_ptr(args->data_ptr); remain = args->size; obj_do_bit17_swizzling = i915_gem_object_needs_bit17_swizzle(obj); @@ -522,7 +522,7 @@ i915_gem_pread_ioctl(struct drm_device *dev, void *data, return 0; if (!access_ok(VERIFY_WRITE, - (char __user *)(uintptr_t)args->data_ptr, + to_user_ptr(args->data_ptr), args->size)) return -EFAULT; @@ -613,7 +613,7 @@ i915_gem_gtt_pwrite_fast(struct drm_device *dev, if (ret) goto out_unpin; - user_data = (char __user *) (uintptr_t) args->data_ptr; + user_data = to_user_ptr(args->data_ptr); remain = args->size; offset = obj->gtt_offset + args->offset; @@ -735,7 +735,7 @@ i915_gem_shmem_pwrite(struct drm_device *dev, int i; struct scatterlist *sg; - user_data = (char __user *) (uintptr_t) args->data_ptr; + user_data = to_user_ptr(args->data_ptr); remain = args->size; obj_do_bit17_swizzling = i915_gem_object_needs_bit17_swizzle(obj); @@ -867,11 +867,11 @@ i915_gem_pwrite_ioctl(struct drm_device *dev, void *data, return 0; if (!access_ok(VERIFY_READ, - (char __user *)(uintptr_t)args->data_ptr, + to_user_ptr(args->data_ptr), args->size)) return -EFAULT; - ret = fault_in_multipages_readable((char __user *)(uintptr_t)args->data_ptr, + ret = fault_in_multipages_readable(to_user_ptr(args->data_ptr), args->size); if (ret) return -EFAULT; @@ -4327,7 +4327,7 @@ i915_gem_phys_pwrite(struct drm_device *dev, struct drm_file *file_priv) { void *vaddr = obj->phys_obj->handle->vaddr + args->offset; - char __user *user_data = (char __user *) (uintptr_t) args->data_ptr; + char __user *user_data = to_user_ptr(args->data_ptr); if (__copy_from_user_inatomic_nocache(vaddr, user_data, args->size)) { unsigned long unwritten; diff --git a/drivers/gpu/drm/i915/i915_gem_execbuffer.c b/drivers/gpu/drm/i915/i915_gem_execbuffer.c index 2f2daebd0eef..934396c5f048 100644 --- a/drivers/gpu/drm/i915/i915_gem_execbuffer.c +++ b/drivers/gpu/drm/i915/i915_gem_execbuffer.c @@ -305,7 +305,7 @@ i915_gem_execbuffer_relocate_object(struct drm_i915_gem_object *obj, struct drm_i915_gem_exec_object2 *entry = obj->exec_entry; int remain, ret; - user_relocs = (void __user *)(uintptr_t)entry->relocs_ptr; + user_relocs = to_user_ptr(entry->relocs_ptr); remain = entry->relocation_count; while (remain) { @@ -618,7 +618,7 @@ i915_gem_execbuffer_relocate_slow(struct drm_device *dev, u64 invalid_offset = (u64)-1; int j; - user_relocs = (void __user *)(uintptr_t)exec[i].relocs_ptr; + user_relocs = to_user_ptr(exec[i].relocs_ptr); if (copy_from_user(reloc+total, user_relocs, exec[i].relocation_count * sizeof(*reloc))) { @@ -734,7 +734,7 @@ validate_exec_list(struct drm_i915_gem_exec_object2 *exec, int i; for (i = 0; i < count; i++) { - char __user *ptr = (char __user *)(uintptr_t)exec[i].relocs_ptr; + char __user *ptr = to_user_ptr(exec[i].relocs_ptr); int length; /* limited by fault_in_pages_readable() */ if (exec[i].flags & __EXEC_OBJECT_UNKNOWN_FLAGS) @@ -944,9 +944,8 @@ i915_gem_do_execbuffer(struct drm_device *dev, void *data, } if (copy_from_user(cliprects, - (struct drm_clip_rect __user *)(uintptr_t) - args->cliprects_ptr, - sizeof(*cliprects)*args->num_cliprects)) { + to_user_ptr(args->cliprects_ptr), + sizeof(*cliprects)*args->num_cliprects)) { ret = -EFAULT; goto pre_mutex_err; } @@ -1110,7 +1109,7 @@ i915_gem_execbuffer(struct drm_device *dev, void *data, return -ENOMEM; } ret = copy_from_user(exec_list, - (void __user *)(uintptr_t)args->buffers_ptr, + to_user_ptr(args->buffers_ptr), sizeof(*exec_list) * args->buffer_count); if (ret != 0) { DRM_DEBUG("copy %d exec entries failed %d\n", @@ -1149,7 +1148,7 @@ i915_gem_execbuffer(struct drm_device *dev, void *data, for (i = 0; i < args->buffer_count; i++) exec_list[i].offset = exec2_list[i].offset; /* ... and back out to userspace */ - ret = copy_to_user((void __user *)(uintptr_t)args->buffers_ptr, + ret = copy_to_user(to_user_ptr(args->buffers_ptr), exec_list, sizeof(*exec_list) * args->buffer_count); if (ret) { @@ -1190,8 +1189,7 @@ i915_gem_execbuffer2(struct drm_device *dev, void *data, return -ENOMEM; } ret = copy_from_user(exec2_list, - (struct drm_i915_relocation_entry __user *) - (uintptr_t) args->buffers_ptr, + to_user_ptr(args->buffers_ptr), sizeof(*exec2_list) * args->buffer_count); if (ret != 0) { DRM_DEBUG("copy %d exec entries failed %d\n", @@ -1203,7 +1201,7 @@ i915_gem_execbuffer2(struct drm_device *dev, void *data, ret = i915_gem_do_execbuffer(dev, data, file, args, exec2_list); if (!ret) { /* Copy the new buffer offsets back to the user's exec list. */ - ret = copy_to_user((void __user *)(uintptr_t)args->buffers_ptr, + ret = copy_to_user(to_user_ptr(args->buffers_ptr), exec2_list, sizeof(*exec2_list) * args->buffer_count); if (ret) { From f4808ab86eed9b829c60b02a9ac5e86f06df0bcf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Thu, 28 Feb 2013 19:19:44 +0200 Subject: [PATCH 23/79] drm/i915: Document the find_pll() function MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The proper use of find_pll() isn't always so easy to determine from the code itself. Some documentation should help. Signed-off-by: Ville Syrjälä Reviewed-by: Chris Wilson Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_display.c | 20 ++++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 878e1e3e0667..b4482b22a1ac 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -71,8 +71,24 @@ typedef struct intel_limit intel_limit_t; struct intel_limit { intel_range_t dot, vco, n, m, m1, m2, p, p1; intel_p2_t p2; - bool (* find_pll)(const intel_limit_t *, struct drm_crtc *, - int, int, intel_clock_t *, intel_clock_t *); + /** + * find_pll() - Find the best values for the PLL + * @limit: limits for the PLL + * @crtc: current CRTC + * @target: target frequency in kHz + * @refclk: reference clock frequency in kHz + * @match_clock: if provided, @best_clock P divider must + * match the P divider from @match_clock + * used for LVDS downclocking + * @best_clock: best PLL values found + * + * Returns true on success, false on failure. + */ + bool (*find_pll)(const intel_limit_t *limit, + struct drm_crtc *crtc, + int target, int refclk, + intel_clock_t *match_clock, + intel_clock_t *best_clock); }; /* FDI */ From 228a0e801b9079d9d3d08f44cb3a722d084df99b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Thu, 28 Feb 2013 19:19:45 +0200 Subject: [PATCH 24/79] drm/i915: Remove a stale and misplaced comment MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The load detection code has moved around at some point, but it left a comment behind. The code now looks to be different enough to make the comment stale as well. Just remove it. Signed-off-by: Ville Syrjälä Reviewed-by: Chris Wilson Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_display.c | 14 -------------- 1 file changed, 14 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index b4482b22a1ac..d33bf78f8f78 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -6454,20 +6454,6 @@ static void intel_crtc_gamma_set(struct drm_crtc *crtc, u16 *red, u16 *green, intel_crtc_load_lut(crtc); } -/** - * Get a pipe with a simple mode set on it for doing load-based monitor - * detection. - * - * It will be up to the load-detect code to adjust the pipe as appropriate for - * its requirements. The pipe will be connected to no other encoders. - * - * Currently this code will only succeed if there is a pipe with no encoders - * configured for it. In the future, it could choose to temporarily disable - * some outputs to free up a pipe for its use. - * - * \return crtc, or NULL if no pipes are available. - */ - /* VESA 640x480x72Hz mode to set on the pipe */ static struct drm_display_mode load_detect_mode = { DRM_MODE("640x480", DRM_MODE_TYPE_DEFAULT, 31500, 640, 664, From 85ce9c67b3eaa1c0465527991cf33581c2b6b1b1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Thu, 28 Feb 2013 19:19:46 +0200 Subject: [PATCH 25/79] drm/i915: Kill a few pointless comments MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The code is totally obvious so these comments serve no purpose. What's worse, one of them was wrong. Just remove them. Signed-off-by: Ville Syrjälä Reviewed-by: Chris Wilson Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_display.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index d33bf78f8f78..9c9716ac7ede 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -487,7 +487,6 @@ static const intel_limit_t *intel_ironlake_limit(struct drm_crtc *crtc, if (intel_pipe_has_type(crtc, INTEL_OUTPUT_LVDS)) { if (intel_is_dual_link_lvds(dev)) { - /* LVDS dual channel */ if (refclk == 100000) limit = &intel_limits_ironlake_dual_lvds_100m; else @@ -514,10 +513,8 @@ static const intel_limit_t *intel_g4x_limit(struct drm_crtc *crtc) if (intel_pipe_has_type(crtc, INTEL_OUTPUT_LVDS)) { if (intel_is_dual_link_lvds(dev)) - /* LVDS with dual channel */ limit = &intel_limits_g4x_dual_channel_lvds; else - /* LVDS with dual channel */ limit = &intel_limits_g4x_single_channel_lvds; } else if (intel_pipe_has_type(crtc, INTEL_OUTPUT_HDMI) || intel_pipe_has_type(crtc, INTEL_OUTPUT_ANALOG)) { From 83983c8b5145542e7533688518ee70665cb87ae6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Fri, 1 Mar 2013 14:35:37 +0200 Subject: [PATCH 26/79] drm/i915: Use FORCEWAKE_KERNEL instead of hardcoded number in MT forcewake ACK MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The MT forcewake ACK register also has a corresponding bit to each of the bits in the MT forcewake register. Use the define we have for the bit we care about instead of a hardcoded number. Signed-off-by: Ville Syrjälä Reviewed-by: Chris Wilson Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_pm.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c index 61fee7fcdc2c..4e1abd04a89b 100644 --- a/drivers/gpu/drm/i915/intel_pm.c +++ b/drivers/gpu/drm/i915/intel_pm.c @@ -4308,7 +4308,7 @@ static void __gen6_gt_force_wake_mt_get(struct drm_i915_private *dev_priv) else forcewake_ack = FORCEWAKE_MT_ACK; - if (wait_for_atomic((I915_READ_NOTRACE(forcewake_ack) & 1) == 0, + if (wait_for_atomic((I915_READ_NOTRACE(forcewake_ack) & FORCEWAKE_KERNEL) == 0, FORCEWAKE_ACK_TIMEOUT_MS)) DRM_ERROR("Timed out waiting for forcewake old ack to clear.\n"); @@ -4316,7 +4316,7 @@ static void __gen6_gt_force_wake_mt_get(struct drm_i915_private *dev_priv) /* something from same cacheline, but !FORCEWAKE_MT */ POSTING_READ(ECOBUS); - if (wait_for_atomic((I915_READ_NOTRACE(forcewake_ack) & 1), + if (wait_for_atomic((I915_READ_NOTRACE(forcewake_ack) & FORCEWAKE_KERNEL), FORCEWAKE_ACK_TIMEOUT_MS)) DRM_ERROR("Timed out waiting for forcewake to ack request.\n"); @@ -4406,13 +4406,13 @@ static void vlv_force_wake_reset(struct drm_i915_private *dev_priv) static void vlv_force_wake_get(struct drm_i915_private *dev_priv) { - if (wait_for_atomic((I915_READ_NOTRACE(FORCEWAKE_ACK_VLV) & 1) == 0, + if (wait_for_atomic((I915_READ_NOTRACE(FORCEWAKE_ACK_VLV) & FORCEWAKE_KERNEL) == 0, FORCEWAKE_ACK_TIMEOUT_MS)) DRM_ERROR("Timed out waiting for forcewake old ack to clear.\n"); I915_WRITE_NOTRACE(FORCEWAKE_VLV, _MASKED_BIT_ENABLE(FORCEWAKE_KERNEL)); - if (wait_for_atomic((I915_READ_NOTRACE(FORCEWAKE_ACK_VLV) & 1), + if (wait_for_atomic((I915_READ_NOTRACE(FORCEWAKE_ACK_VLV) & FORCEWAKE_KERNEL), FORCEWAKE_ACK_TIMEOUT_MS)) DRM_ERROR("Timed out waiting for forcewake to ack request.\n"); From 30771e1652391e7fabef9f276e1579b8ecd76955 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Fri, 1 Mar 2013 14:35:38 +0200 Subject: [PATCH 27/79] drm/i915: Use '1' instead of FORCEWAKE_KERNEL for ST force wake MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Use the number '1' instead of FORCEWAKE_KERNEL when requesting single thread force wake since there is only one bit in the register. Using the FORCEWAKE_KERNEL name might give someone the wrong impression. Signed-off-by: Ville Syrjälä Reviewed-by: Chris Wilson Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_pm.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c index 4e1abd04a89b..2d4ec08383dd 100644 --- a/drivers/gpu/drm/i915/intel_pm.c +++ b/drivers/gpu/drm/i915/intel_pm.c @@ -4282,7 +4282,7 @@ static void __gen6_gt_force_wake_get(struct drm_i915_private *dev_priv) FORCEWAKE_ACK_TIMEOUT_MS)) DRM_ERROR("Timed out waiting for forcewake old ack to clear.\n"); - I915_WRITE_NOTRACE(FORCEWAKE, FORCEWAKE_KERNEL); + I915_WRITE_NOTRACE(FORCEWAKE, 1); POSTING_READ(ECOBUS); /* something from same cacheline, but !FORCEWAKE */ if (wait_for_atomic((I915_READ_NOTRACE(forcewake_ack) & 1), From ebd37ce1f74e1b735dc094334ad99d17ec66926b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Fri, 1 Mar 2013 14:35:39 +0200 Subject: [PATCH 28/79] drm/i915: Single thread force wake isn't used on HSW anymore MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Kill the HSW check from the single thread force wake code. HSW uses MT force wake exclusively these days. The commit that removed HSW single thread forcewake support: commit 36ec8f877481449bdfa072e6adf2060869e2b970 Author: Daniel Vetter Date: Thu Oct 18 14:44:35 2012 +0200 drm/i915: unconditionally use mt forcewake on hsw/ivb Signed-off-by: Ville Syrjälä Reviewed-by: Chris Wilson Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_pm.c | 11 ++--------- 1 file changed, 2 insertions(+), 9 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c index 2d4ec08383dd..5479363083c6 100644 --- a/drivers/gpu/drm/i915/intel_pm.c +++ b/drivers/gpu/drm/i915/intel_pm.c @@ -4271,21 +4271,14 @@ static void __gen6_gt_force_wake_reset(struct drm_i915_private *dev_priv) static void __gen6_gt_force_wake_get(struct drm_i915_private *dev_priv) { - u32 forcewake_ack; - - if (IS_HASWELL(dev_priv->dev)) - forcewake_ack = FORCEWAKE_ACK_HSW; - else - forcewake_ack = FORCEWAKE_ACK; - - if (wait_for_atomic((I915_READ_NOTRACE(forcewake_ack) & 1) == 0, + if (wait_for_atomic((I915_READ_NOTRACE(FORCEWAKE_ACK) & 1) == 0, FORCEWAKE_ACK_TIMEOUT_MS)) DRM_ERROR("Timed out waiting for forcewake old ack to clear.\n"); I915_WRITE_NOTRACE(FORCEWAKE, 1); POSTING_READ(ECOBUS); /* something from same cacheline, but !FORCEWAKE */ - if (wait_for_atomic((I915_READ_NOTRACE(forcewake_ack) & 1), + if (wait_for_atomic((I915_READ_NOTRACE(FORCEWAKE_ACK) & 1), FORCEWAKE_ACK_TIMEOUT_MS)) DRM_ERROR("Timed out waiting for forcewake to ack request.\n"); From d0d045e8f5164da9f1a06c1214e4f7ec235ca104 Mon Sep 17 00:00:00 2001 From: Ben Widawsky Date: Sun, 24 Feb 2013 18:10:00 -0800 Subject: [PATCH 29/79] drm/i915: Created a sized object error dump v2: Actually use num_pages (Chris) Cc: Chris Wilson Signed-off-by: Ben Widawsky Reviewed-by: Chris Wilson Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_irq.c | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c index 4cbbbd688935..97b65f079b30 100644 --- a/drivers/gpu/drm/i915/i915_irq.c +++ b/drivers/gpu/drm/i915/i915_irq.c @@ -956,24 +956,23 @@ static void i915_get_extra_instdone(struct drm_device *dev, #ifdef CONFIG_DEBUG_FS static struct drm_i915_error_object * -i915_error_object_create(struct drm_i915_private *dev_priv, - struct drm_i915_gem_object *src) +i915_error_object_create_sized(struct drm_i915_private *dev_priv, + struct drm_i915_gem_object *src, + const int num_pages) { struct drm_i915_error_object *dst; - int i, count; + int i; u32 reloc_offset; if (src == NULL || src->pages == NULL) return NULL; - count = src->base.size / PAGE_SIZE; - - dst = kmalloc(sizeof(*dst) + count * sizeof(u32 *), GFP_ATOMIC); + dst = kmalloc(sizeof(*dst) + num_pages * sizeof(u32 *), GFP_ATOMIC); if (dst == NULL) return NULL; reloc_offset = src->gtt_offset; - for (i = 0; i < count; i++) { + for (i = 0; i < num_pages; i++) { unsigned long flags; void *d; @@ -1023,7 +1022,7 @@ i915_error_object_create(struct drm_i915_private *dev_priv, reloc_offset += PAGE_SIZE; } - dst->page_count = count; + dst->page_count = num_pages; dst->gtt_offset = src->gtt_offset; return dst; @@ -1034,6 +1033,9 @@ unwind: kfree(dst); return NULL; } +#define i915_error_object_create(dev_priv, src) \ + i915_error_object_create_sized((dev_priv), (src), \ + (src)->base.size>>PAGE_SHIFT) static void i915_error_object_free(struct drm_i915_error_object *obj) From 211816eccb494b25f96e6bd492292d9d1f6ffda5 Mon Sep 17 00:00:00 2001 From: Ben Widawsky Date: Sun, 24 Feb 2013 18:10:01 -0800 Subject: [PATCH 30/79] drm/i915: exclude CCID for platforms without it Signed-off-by: Ben Widawsky Reviewed-by: Chris Wilson 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 97b65f079b30..12561f2f7fd7 100644 --- a/drivers/gpu/drm/i915/i915_irq.c +++ b/drivers/gpu/drm/i915/i915_irq.c @@ -1321,7 +1321,8 @@ static void i915_capture_error_state(struct drm_device *dev) kref_init(&error->ref); error->eir = I915_READ(EIR); error->pgtbl_er = I915_READ(PGTBL_ER); - error->ccid = I915_READ(CCID); + if (HAS_HW_CONTEXTS(dev)) + error->ccid = I915_READ(CCID); if (HAS_PCH_SPLIT(dev)) error->ier = I915_READ(DEIER) | I915_READ(GTIER); From da1a62acd01c1fe09bc7019b36412f50a43d0e2d Mon Sep 17 00:00:00 2001 From: Jesse Barnes Date: Tue, 19 Feb 2013 12:11:43 -0800 Subject: [PATCH 31/79] drm/i915: remove disabled memset of framebuffer from intel_fb Commented out and unneeded. Signed-off-by: Jesse Barnes Reviewed-by: Paulo Zanoni Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_fb.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_fb.c b/drivers/gpu/drm/i915/intel_fb.c index 1c510da04d16..953ee7387d6a 100644 --- a/drivers/gpu/drm/i915/intel_fb.c +++ b/drivers/gpu/drm/i915/intel_fb.c @@ -149,8 +149,6 @@ static int intelfb_create(struct intel_fbdev *ifbdev, } info->screen_size = size; -// memset(info->screen_base, 0, size); - drm_fb_helper_fill_fix(info, fb->pitches[0], fb->depth); drm_fb_helper_fill_var(info, &ifbdev->helper, sizes->fb_width, sizes->fb_height); From e2debe919a859a350a542a361705a51e4567b6db Mon Sep 17 00:00:00 2001 From: Paulo Zanoni Date: Mon, 18 Feb 2013 19:00:27 -0300 Subject: [PATCH 32/79] drm/i915: clarify confusion between SDVO and HDMI registers Some HDMI registers can be used for SDVO, so saying "HDMIB" should be the same as saying "SDVOB" for a given HW generation. This was not true and led to confusions and even a regression. Previously we had: - SDVO{B,C} defined as the Gen3+ registers - HDMI{B,C,D} and PCH_SDVOB defined as the PCH registers But now: - SDVO{B,C} became GEN3_SDVO{B,C} on SDVO code - SDVO{B,C} became GEN4_HDMI{B,C} on HDMI code - HDMI{B,C,D} became PCH_HDMI{B,C,D} - PCH_SDVOB is still the same thing v2: Rebase (v1 was sent in May 2012). Signed-off-by: Paulo Zanoni Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_reg.h | 19 ++++++------- drivers/gpu/drm/i915/intel_display.c | 42 +++++++++++++++------------- drivers/gpu/drm/i915/intel_sdvo.c | 22 +++++++-------- 3 files changed, 42 insertions(+), 41 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index c6d482fdf89b..448e13c26c87 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -1681,8 +1681,9 @@ #define SDVOB_HOTPLUG_INT_STATUS_I915 (1 << 6) /* SDVO port control */ -#define SDVOB 0x61140 -#define SDVOC 0x61160 +#define GEN3_SDVOB 0x61140 +#define GEN3_SDVOC 0x61160 +#define PCH_SDVOB 0xe1140 #define SDVO_ENABLE (1 << 31) #define SDVO_PIPE_B_SELECT (1 << 30) #define SDVO_STALL_SELECT (1 << 29) @@ -3982,8 +3983,12 @@ #define FDI_PLL_CTL_1 0xfe000 #define FDI_PLL_CTL_2 0xfe004 -/* or SDVOB */ -#define HDMIB 0xe1140 +/* The same register may be used for SDVO or HDMI */ +#define GEN4_HDMIB GEN3_SDVOB +#define GEN4_HDMIC GEN3_SDVOC +#define PCH_HDMIB PCH_SDVOB +#define PCH_HDMIC 0xe1150 +#define PCH_HDMID 0xe1160 #define PORT_ENABLE (1 << 31) #define TRANSCODER(pipe) ((pipe) << 30) #define TRANSCODER_CPT(pipe) ((pipe) << 29) @@ -4004,12 +4009,6 @@ #define HSYNC_ACTIVE_HIGH (1 << 3) #define PORT_DETECTED (1 << 2) -/* PCH SDVOB multiplex with HDMIB */ -#define PCH_SDVOB HDMIB - -#define HDMIC 0xe1150 -#define HDMID 0xe1160 - #define PCH_LVDS 0xe1180 #define LVDS_DETECTED (1 << 1) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 9c9716ac7ede..1048046fcb6e 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -1432,9 +1432,9 @@ static void assert_pch_ports_disabled(struct drm_i915_private *dev_priv, "PCH LVDS enabled on transcoder %c, should be disabled\n", pipe_name(pipe)); - assert_pch_hdmi_disabled(dev_priv, pipe, HDMIB); - assert_pch_hdmi_disabled(dev_priv, pipe, HDMIC); - assert_pch_hdmi_disabled(dev_priv, pipe, HDMID); + assert_pch_hdmi_disabled(dev_priv, pipe, PCH_HDMIB); + assert_pch_hdmi_disabled(dev_priv, pipe, PCH_HDMIC); + assert_pch_hdmi_disabled(dev_priv, pipe, PCH_HDMID); } /** @@ -8352,20 +8352,20 @@ static void intel_setup_outputs(struct drm_device *dev) if (has_edp_a(dev)) intel_dp_init(dev, DP_A, PORT_A); - if (I915_READ(HDMIB) & PORT_DETECTED) { + if (I915_READ(PCH_HDMIB) & PORT_DETECTED) { /* PCH SDVOB multiplex with HDMIB */ found = intel_sdvo_init(dev, PCH_SDVOB, true); if (!found) - intel_hdmi_init(dev, HDMIB, PORT_B); + intel_hdmi_init(dev, PCH_HDMIB, PORT_B); if (!found && (I915_READ(PCH_DP_B) & DP_DETECTED)) intel_dp_init(dev, PCH_DP_B, PORT_B); } - if (I915_READ(HDMIC) & PORT_DETECTED) - intel_hdmi_init(dev, HDMIC, PORT_C); + if (I915_READ(PCH_HDMIC) & PORT_DETECTED) + intel_hdmi_init(dev, PCH_HDMIC, PORT_C); - if (!dpd_is_edp && I915_READ(HDMID) & PORT_DETECTED) - intel_hdmi_init(dev, HDMID, PORT_D); + if (!dpd_is_edp && I915_READ(PCH_HDMID) & PORT_DETECTED) + intel_hdmi_init(dev, PCH_HDMID, PORT_D); if (I915_READ(PCH_DP_C) & DP_DETECTED) intel_dp_init(dev, PCH_DP_C, PORT_C); @@ -8377,24 +8377,26 @@ static void intel_setup_outputs(struct drm_device *dev) if (I915_READ(VLV_DISPLAY_BASE + DP_C) & DP_DETECTED) intel_dp_init(dev, VLV_DISPLAY_BASE + DP_C, PORT_C); - 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 + GEN4_HDMIB) & PORT_DETECTED) { + intel_hdmi_init(dev, VLV_DISPLAY_BASE + GEN4_HDMIB, + 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(VLV_DISPLAY_BASE + SDVOC) & PORT_DETECTED) - intel_hdmi_init(dev, VLV_DISPLAY_BASE + SDVOC, PORT_C); + if (I915_READ(VLV_DISPLAY_BASE + GEN4_HDMIC) & PORT_DETECTED) + intel_hdmi_init(dev, VLV_DISPLAY_BASE + GEN4_HDMIC, + PORT_C); } else if (SUPPORTS_DIGITAL_OUTPUTS(dev)) { bool found = false; - if (I915_READ(SDVOB) & SDVO_DETECTED) { + if (I915_READ(GEN3_SDVOB) & SDVO_DETECTED) { DRM_DEBUG_KMS("probing SDVOB\n"); - found = intel_sdvo_init(dev, SDVOB, true); + found = intel_sdvo_init(dev, GEN3_SDVOB, true); if (!found && SUPPORTS_INTEGRATED_HDMI(dev)) { DRM_DEBUG_KMS("probing HDMI on SDVOB\n"); - intel_hdmi_init(dev, SDVOB, PORT_B); + intel_hdmi_init(dev, GEN4_HDMIB, PORT_B); } if (!found && SUPPORTS_INTEGRATED_DP(dev)) { @@ -8405,16 +8407,16 @@ static void intel_setup_outputs(struct drm_device *dev) /* Before G4X SDVOC doesn't have its own detect register */ - if (I915_READ(SDVOB) & SDVO_DETECTED) { + if (I915_READ(GEN3_SDVOB) & SDVO_DETECTED) { DRM_DEBUG_KMS("probing SDVOC\n"); - found = intel_sdvo_init(dev, SDVOC, false); + found = intel_sdvo_init(dev, GEN3_SDVOC, false); } - if (!found && (I915_READ(SDVOC) & SDVO_DETECTED)) { + if (!found && (I915_READ(GEN3_SDVOC) & SDVO_DETECTED)) { if (SUPPORTS_INTEGRATED_HDMI(dev)) { DRM_DEBUG_KMS("probing HDMI on SDVOC\n"); - intel_hdmi_init(dev, SDVOC, PORT_C); + intel_hdmi_init(dev, GEN4_HDMIC, PORT_C); } if (SUPPORTS_INTEGRATED_DP(dev)) { DRM_DEBUG_KMS("probing DP_C\n"); diff --git a/drivers/gpu/drm/i915/intel_sdvo.c b/drivers/gpu/drm/i915/intel_sdvo.c index f01063a2323a..7d94db8559ee 100644 --- a/drivers/gpu/drm/i915/intel_sdvo.c +++ b/drivers/gpu/drm/i915/intel_sdvo.c @@ -246,11 +246,11 @@ static void intel_sdvo_write_sdvox(struct intel_sdvo *intel_sdvo, u32 val) return; } - if (intel_sdvo->sdvo_reg == SDVOB) { - cval = I915_READ(SDVOC); - } else { - bval = I915_READ(SDVOB); - } + if (intel_sdvo->sdvo_reg == GEN3_SDVOB) + cval = I915_READ(GEN3_SDVOC); + else + bval = I915_READ(GEN3_SDVOB); + /* * Write the registers twice for luck. Sometimes, * writing them only once doesn't appear to 'stick'. @@ -258,10 +258,10 @@ static void intel_sdvo_write_sdvox(struct intel_sdvo *intel_sdvo, u32 val) */ for (i = 0; i < 2; i++) { - I915_WRITE(SDVOB, bval); - I915_READ(SDVOB); - I915_WRITE(SDVOC, cval); - I915_READ(SDVOC); + I915_WRITE(GEN3_SDVOB, bval); + I915_READ(GEN3_SDVOB); + I915_WRITE(GEN3_SDVOC, cval); + I915_READ(GEN3_SDVOC); } } @@ -1182,10 +1182,10 @@ static void intel_sdvo_mode_set(struct drm_encoder *encoder, } else { sdvox = I915_READ(intel_sdvo->sdvo_reg); switch (intel_sdvo->sdvo_reg) { - case SDVOB: + case GEN3_SDVOB: sdvox &= SDVOB_PRESERVE_MASK; break; - case SDVOC: + case GEN3_SDVOC: sdvox &= SDVOC_PRESERVE_MASK; break; } From c20cd31252554b927ae1cce1c71ae8a769b1bd74 Mon Sep 17 00:00:00 2001 From: Paulo Zanoni Date: Tue, 19 Feb 2013 16:21:45 -0300 Subject: [PATCH 33/79] drm/i915: unify the definitions of the HDMI/SDVO register Since they're all the same register, leave all the #defines at the same place, organized by Gen and also specify which bits are used by only a specific port or encoding. Also remove a few unused duplicates and adjust indentation. Signed-off-by: Paulo Zanoni Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_reg.h | 111 ++++++++++++++++---------------- 1 file changed, 55 insertions(+), 56 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index 448e13c26c87..330b64d2614a 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -1680,43 +1680,68 @@ #define SDVOC_HOTPLUG_INT_STATUS_I915 (1 << 7) #define SDVOB_HOTPLUG_INT_STATUS_I915 (1 << 6) -/* SDVO port control */ -#define GEN3_SDVOB 0x61140 -#define GEN3_SDVOC 0x61160 -#define PCH_SDVOB 0xe1140 -#define SDVO_ENABLE (1 << 31) -#define SDVO_PIPE_B_SELECT (1 << 30) -#define SDVO_STALL_SELECT (1 << 29) -#define SDVO_INTERRUPT_ENABLE (1 << 26) +/* SDVO and HDMI port control. + * The same register may be used for SDVO or HDMI */ +#define GEN3_SDVOB 0x61140 +#define GEN3_SDVOC 0x61160 +#define GEN4_HDMIB GEN3_SDVOB +#define GEN4_HDMIC GEN3_SDVOC +#define PCH_SDVOB 0xe1140 +#define PCH_HDMIB PCH_SDVOB +#define PCH_HDMIC 0xe1150 +#define PCH_HDMID 0xe1160 + +/* Gen 3 SDVO bits: */ +#define SDVO_ENABLE (1 << 31) +#define SDVO_PIPE_B_SELECT (1 << 30) +#define SDVO_STALL_SELECT (1 << 29) +#define SDVO_INTERRUPT_ENABLE (1 << 26) /** * 915G/GM SDVO pixel multiplier. - * * Programmed value is multiplier - 1, up to 5x. - * * \sa DPLL_MD_UDI_MULTIPLIER_MASK */ -#define SDVO_PORT_MULTIPLY_MASK (7 << 23) +#define SDVO_PORT_MULTIPLY_MASK (7 << 23) #define SDVO_PORT_MULTIPLY_SHIFT 23 -#define SDVO_PHASE_SELECT_MASK (15 << 19) -#define SDVO_PHASE_SELECT_DEFAULT (6 << 19) -#define SDVO_CLOCK_OUTPUT_INVERT (1 << 18) -#define SDVOC_GANG_MODE (1 << 16) -#define SDVO_ENCODING_SDVO (0x0 << 10) -#define SDVO_ENCODING_HDMI (0x2 << 10) -/** Requird for HDMI operation */ -#define SDVO_NULL_PACKETS_DURING_VSYNC (1 << 9) -#define SDVO_COLOR_RANGE_16_235 (1 << 8) -#define SDVO_BORDER_ENABLE (1 << 7) -#define SDVO_AUDIO_ENABLE (1 << 6) -/** New with 965, default is to be set */ -#define SDVO_VSYNC_ACTIVE_HIGH (1 << 4) -/** New with 965, default is to be set */ -#define SDVO_HSYNC_ACTIVE_HIGH (1 << 3) -#define SDVOB_PCIE_CONCURRENCY (1 << 3) -#define SDVO_DETECTED (1 << 2) +#define SDVO_PHASE_SELECT_MASK (15 << 19) +#define SDVO_PHASE_SELECT_DEFAULT (6 << 19) +#define SDVO_CLOCK_OUTPUT_INVERT (1 << 18) +#define SDVOC_GANG_MODE (1 << 16) /* Port C only */ +#define SDVO_BORDER_ENABLE (1 << 7) /* SDVO only */ +#define SDVOB_PCIE_CONCURRENCY (1 << 3) /* Port B only */ +#define SDVO_DETECTED (1 << 2) /* Bits to be preserved when writing */ -#define SDVOB_PRESERVE_MASK ((1 << 17) | (1 << 16) | (1 << 14) | (1 << 26)) -#define SDVOC_PRESERVE_MASK ((1 << 17) | (1 << 26)) +#define SDVOB_PRESERVE_MASK ((1 << 17) | (1 << 16) | (1 << 14) | \ + SDVO_INTERRUPT_ENABLE) +#define SDVOC_PRESERVE_MASK ((1 << 17) | SDVO_INTERRUPT_ENABLE) + +/* Gen 4 SDVO/HDMI bits: */ +#define COLOR_FORMAT_8bpc (0 << 26) +#define SDVO_ENCODING_SDVO (0 << 10) +#define SDVO_ENCODING_HDMI (2 << 10) +#define SDVO_NULL_PACKETS_DURING_VSYNC (1 << 9) /* HDMI only */ +#define SDVO_COLOR_RANGE_16_235 (1 << 8) /* HDMI only */ +#define SDVO_AUDIO_ENABLE (1 << 6) +/* VSYNC/HSYNC bits new with 965, default is to be set */ +#define SDVO_VSYNC_ACTIVE_HIGH (1 << 4) +#define SDVO_HSYNC_ACTIVE_HIGH (1 << 3) + +/* Gen 5 (IBX) SDVO/HDMI bits: */ +#define COLOR_FORMAT_12bpc (3 << 26) /* HDMI only */ +#define SDVOB_HOTPLUG_ENABLE (1 << 23) /* SDVO only */ + +/* Gen 6 (CPT) SDVO/HDMI bits: */ +#define TRANSCODER_CPT(pipe) ((pipe) << 29) +#define TRANSCODER_MASK_CPT (3 << 29) + +/* Repeated but still used bits: */ +#define PORT_ENABLE (1 << 31) +#define TRANSCODER(pipe) ((pipe) << 30) +#define TRANSCODER_MASK (1 << 30) +#define HDMI_MODE_SELECT (1 << 9) +#define DVI_MODE_SELECT (0 << 9) +#define PORT_DETECTED (1 << 2) + /* DVO port control */ #define DVOA 0x61120 @@ -3983,32 +4008,6 @@ #define FDI_PLL_CTL_1 0xfe000 #define FDI_PLL_CTL_2 0xfe004 -/* The same register may be used for SDVO or HDMI */ -#define GEN4_HDMIB GEN3_SDVOB -#define GEN4_HDMIC GEN3_SDVOC -#define PCH_HDMIB PCH_SDVOB -#define PCH_HDMIC 0xe1150 -#define PCH_HDMID 0xe1160 -#define PORT_ENABLE (1 << 31) -#define TRANSCODER(pipe) ((pipe) << 30) -#define TRANSCODER_CPT(pipe) ((pipe) << 29) -#define TRANSCODER_MASK (1 << 30) -#define TRANSCODER_MASK_CPT (3 << 29) -#define COLOR_FORMAT_8bpc (0) -#define COLOR_FORMAT_12bpc (3 << 26) -#define SDVOB_HOTPLUG_ENABLE (1 << 23) -#define SDVO_ENCODING (0) -#define TMDS_ENCODING (2 << 10) -#define NULL_PACKET_VSYNC_ENABLE (1 << 9) -/* CPT */ -#define HDMI_MODE_SELECT (1 << 9) -#define DVI_MODE_SELECT (0) -#define SDVOB_BORDER_ENABLE (1 << 7) -#define AUDIO_ENABLE (1 << 6) -#define VSYNC_ACTIVE_HIGH (1 << 4) -#define HSYNC_ACTIVE_HIGH (1 << 3) -#define PORT_DETECTED (1 << 2) - #define PCH_LVDS 0xe1180 #define LVDS_DETECTED (1 << 1) From dc0fa7181132b1fde269accc4e067b8b833f34ef Mon Sep 17 00:00:00 2001 From: Paulo Zanoni Date: Tue, 19 Feb 2013 16:21:46 -0300 Subject: [PATCH 34/79] drm/i915: remove duplicated SDVO/HDMI bit definitions Signed-off-by: Paulo Zanoni Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_reg.h | 17 ++++++----------- drivers/gpu/drm/i915/intel_display.c | 18 +++++++++--------- drivers/gpu/drm/i915/intel_hdmi.c | 23 +++++++++-------------- drivers/gpu/drm/i915/intel_sdvo.c | 16 +++++----------- 4 files changed, 29 insertions(+), 45 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index 330b64d2614a..f62e4e5014bc 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -1693,6 +1693,8 @@ /* Gen 3 SDVO bits: */ #define SDVO_ENABLE (1 << 31) +#define SDVO_PIPE_SEL(pipe) ((pipe) << 30) +#define SDVO_PIPE_SEL_MASK (1 << 30) #define SDVO_PIPE_B_SELECT (1 << 30) #define SDVO_STALL_SELECT (1 << 29) #define SDVO_INTERRUPT_ENABLE (1 << 26) @@ -1719,7 +1721,8 @@ #define COLOR_FORMAT_8bpc (0 << 26) #define SDVO_ENCODING_SDVO (0 << 10) #define SDVO_ENCODING_HDMI (2 << 10) -#define SDVO_NULL_PACKETS_DURING_VSYNC (1 << 9) /* HDMI only */ +#define HDMI_MODE_SELECT_HDMI (1 << 9) /* HDMI only */ +#define HDMI_MODE_SELECT_DVI (0 << 9) /* HDMI only */ #define SDVO_COLOR_RANGE_16_235 (1 << 8) /* HDMI only */ #define SDVO_AUDIO_ENABLE (1 << 6) /* VSYNC/HSYNC bits new with 965, default is to be set */ @@ -1731,16 +1734,8 @@ #define SDVOB_HOTPLUG_ENABLE (1 << 23) /* SDVO only */ /* Gen 6 (CPT) SDVO/HDMI bits: */ -#define TRANSCODER_CPT(pipe) ((pipe) << 29) -#define TRANSCODER_MASK_CPT (3 << 29) - -/* Repeated but still used bits: */ -#define PORT_ENABLE (1 << 31) -#define TRANSCODER(pipe) ((pipe) << 30) -#define TRANSCODER_MASK (1 << 30) -#define HDMI_MODE_SELECT (1 << 9) -#define DVI_MODE_SELECT (0 << 9) -#define PORT_DETECTED (1 << 2) +#define SDVO_PIPE_SEL_CPT(pipe) ((pipe) << 29) +#define SDVO_PIPE_SEL_MASK_CPT (3 << 29) /* DVO port control */ diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 1048046fcb6e..502cb28a46c9 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -1340,14 +1340,14 @@ static bool dp_pipe_enabled(struct drm_i915_private *dev_priv, static bool hdmi_pipe_enabled(struct drm_i915_private *dev_priv, enum pipe pipe, u32 val) { - if ((val & PORT_ENABLE) == 0) + if ((val & SDVO_ENABLE) == 0) return false; if (HAS_PCH_CPT(dev_priv->dev)) { - if ((val & PORT_TRANS_SEL_MASK) != PORT_TRANS_SEL_CPT(pipe)) + if ((val & SDVO_PIPE_SEL_MASK_CPT) != SDVO_PIPE_SEL_CPT(pipe)) return false; } else { - if ((val & TRANSCODER_MASK) != TRANSCODER(pipe)) + if ((val & SDVO_PIPE_SEL_MASK) != SDVO_PIPE_SEL(pipe)) return false; } return true; @@ -1405,7 +1405,7 @@ static void assert_pch_hdmi_disabled(struct drm_i915_private *dev_priv, "PCH HDMI (0x%08x) enabled on transcoder %c, should be disabled\n", reg, pipe_name(pipe)); - WARN(HAS_PCH_IBX(dev_priv->dev) && (val & PORT_ENABLE) == 0 + WARN(HAS_PCH_IBX(dev_priv->dev) && (val & SDVO_ENABLE) == 0 && (val & SDVO_PIPE_B_SELECT), "IBX PCH hdmi port still using transcoder B\n"); } @@ -8352,7 +8352,7 @@ static void intel_setup_outputs(struct drm_device *dev) if (has_edp_a(dev)) intel_dp_init(dev, DP_A, PORT_A); - if (I915_READ(PCH_HDMIB) & PORT_DETECTED) { + if (I915_READ(PCH_HDMIB) & SDVO_DETECTED) { /* PCH SDVOB multiplex with HDMIB */ found = intel_sdvo_init(dev, PCH_SDVOB, true); if (!found) @@ -8361,10 +8361,10 @@ static void intel_setup_outputs(struct drm_device *dev) intel_dp_init(dev, PCH_DP_B, PORT_B); } - if (I915_READ(PCH_HDMIC) & PORT_DETECTED) + if (I915_READ(PCH_HDMIC) & SDVO_DETECTED) intel_hdmi_init(dev, PCH_HDMIC, PORT_C); - if (!dpd_is_edp && I915_READ(PCH_HDMID) & PORT_DETECTED) + if (!dpd_is_edp && I915_READ(PCH_HDMID) & SDVO_DETECTED) intel_hdmi_init(dev, PCH_HDMID, PORT_D); if (I915_READ(PCH_DP_C) & DP_DETECTED) @@ -8377,14 +8377,14 @@ static void intel_setup_outputs(struct drm_device *dev) if (I915_READ(VLV_DISPLAY_BASE + DP_C) & DP_DETECTED) intel_dp_init(dev, VLV_DISPLAY_BASE + DP_C, PORT_C); - if (I915_READ(VLV_DISPLAY_BASE + GEN4_HDMIB) & PORT_DETECTED) { + if (I915_READ(VLV_DISPLAY_BASE + GEN4_HDMIB) & SDVO_DETECTED) { intel_hdmi_init(dev, VLV_DISPLAY_BASE + GEN4_HDMIB, 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(VLV_DISPLAY_BASE + GEN4_HDMIC) & PORT_DETECTED) + if (I915_READ(VLV_DISPLAY_BASE + GEN4_HDMIC) & SDVO_DETECTED) intel_hdmi_init(dev, VLV_DISPLAY_BASE + GEN4_HDMIC, PORT_C); diff --git a/drivers/gpu/drm/i915/intel_hdmi.c b/drivers/gpu/drm/i915/intel_hdmi.c index 6046db0e9f8a..0b42ba31d402 100644 --- a/drivers/gpu/drm/i915/intel_hdmi.c +++ b/drivers/gpu/drm/i915/intel_hdmi.c @@ -615,20 +615,20 @@ static void intel_hdmi_mode_set(struct drm_encoder *encoder, /* Required on CPT */ if (intel_hdmi->has_hdmi_sink && HAS_PCH_CPT(dev)) - hdmi_val |= HDMI_MODE_SELECT; + hdmi_val |= HDMI_MODE_SELECT_HDMI; if (intel_hdmi->has_audio) { DRM_DEBUG_DRIVER("Enabling HDMI audio on pipe %c\n", pipe_name(intel_crtc->pipe)); hdmi_val |= SDVO_AUDIO_ENABLE; - hdmi_val |= SDVO_NULL_PACKETS_DURING_VSYNC; + hdmi_val |= HDMI_MODE_SELECT_HDMI; intel_write_eld(encoder, adjusted_mode); } if (HAS_PCH_CPT(dev)) - hdmi_val |= PORT_TRANS_SEL_CPT(intel_crtc->pipe); - else if (intel_crtc->pipe == PIPE_B) - hdmi_val |= SDVO_PIPE_B_SELECT; + hdmi_val |= SDVO_PIPE_SEL_CPT(intel_crtc->pipe); + else + hdmi_val |= SDVO_PIPE_SEL(intel_crtc->pipe); I915_WRITE(intel_hdmi->hdmi_reg, hdmi_val); POSTING_READ(intel_hdmi->hdmi_reg); @@ -661,6 +661,7 @@ static void intel_enable_hdmi(struct intel_encoder *encoder) { struct drm_device *dev = encoder->base.dev; struct drm_i915_private *dev_priv = dev->dev_private; + struct intel_crtc *intel_crtc = to_intel_crtc(encoder->base.crtc); struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(&encoder->base); u32 temp; u32 enable_bits = SDVO_ENABLE; @@ -671,15 +672,9 @@ static void intel_enable_hdmi(struct intel_encoder *encoder) temp = I915_READ(intel_hdmi->hdmi_reg); /* HW workaround for IBX, we need to move the port to transcoder A - * before disabling it. */ - if (HAS_PCH_IBX(dev)) { - struct drm_crtc *crtc = encoder->base.crtc; - int pipe = crtc ? to_intel_crtc(crtc)->pipe : -1; - - /* Restore the transcoder select bit. */ - if (pipe == PIPE_B) - enable_bits |= SDVO_PIPE_B_SELECT; - } + * before disabling it, so restore the transcoder select bit here. */ + if (HAS_PCH_IBX(dev)) + enable_bits |= SDVO_PIPE_SEL(intel_crtc->pipe); /* HW workaround, need to toggle enable bit off and on for 12bpc, but * we do this anyway which shows more stable in testing. diff --git a/drivers/gpu/drm/i915/intel_sdvo.c b/drivers/gpu/drm/i915/intel_sdvo.c index 7d94db8559ee..eef073114f7a 100644 --- a/drivers/gpu/drm/i915/intel_sdvo.c +++ b/drivers/gpu/drm/i915/intel_sdvo.c @@ -1193,9 +1193,9 @@ static void intel_sdvo_mode_set(struct drm_encoder *encoder, } if (INTEL_PCH_TYPE(dev) >= PCH_CPT) - sdvox |= TRANSCODER_CPT(intel_crtc->pipe); + sdvox |= SDVO_PIPE_SEL_CPT(intel_crtc->pipe); else - sdvox |= TRANSCODER(intel_crtc->pipe); + sdvox |= SDVO_PIPE_SEL(intel_crtc->pipe); if (intel_sdvo->has_hdmi_audio) sdvox |= SDVO_AUDIO_ENABLE; @@ -1305,15 +1305,9 @@ static void intel_enable_sdvo(struct intel_encoder *encoder) temp = I915_READ(intel_sdvo->sdvo_reg); if ((temp & SDVO_ENABLE) == 0) { /* HW workaround for IBX, we need to move the port - * to transcoder A before disabling it. */ - if (HAS_PCH_IBX(dev)) { - struct drm_crtc *crtc = encoder->base.crtc; - int pipe = crtc ? to_intel_crtc(crtc)->pipe : -1; - - /* Restore the transcoder select bit. */ - if (pipe == PIPE_B) - temp |= SDVO_PIPE_B_SELECT; - } + * to transcoder A before disabling it, so restore it here. */ + if (HAS_PCH_IBX(dev)) + temp |= SDVO_PIPE_SEL(intel_crtc->pipe); intel_sdvo_write_sdvox(intel_sdvo, temp | SDVO_ENABLE); } From 4f3a8bc7ba6e34403f36e600bc6f54cf0e0041e4 Mon Sep 17 00:00:00 2001 From: Paulo Zanoni Date: Tue, 19 Feb 2013 16:21:47 -0300 Subject: [PATCH 35/79] drm/i915: rename some HDMI bit definitions Bits used only on HDMI mode now have HDMI_ prefix instead of SDVO_. The COLOR_FORMAT bits now have prefixes (and the 12bpc bit is for HDMI only). Notice that this patch uncovers a bug on the SDVO code: the COLOR_RANGE_16_235 bit can only be used if the port is in TMDS mode, not SDVO mode. This will have to be fixed in a later patch. Signed-off-by: Paulo Zanoni Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_reg.h | 6 +++--- drivers/gpu/drm/i915/intel_hdmi.c | 8 ++++---- drivers/gpu/drm/i915/intel_sdvo.c | 8 ++++++-- 3 files changed, 13 insertions(+), 9 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index f62e4e5014bc..4cf3eceb5153 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -1718,19 +1718,19 @@ #define SDVOC_PRESERVE_MASK ((1 << 17) | SDVO_INTERRUPT_ENABLE) /* Gen 4 SDVO/HDMI bits: */ -#define COLOR_FORMAT_8bpc (0 << 26) +#define SDVO_COLOR_FORMAT_8bpc (0 << 26) #define SDVO_ENCODING_SDVO (0 << 10) #define SDVO_ENCODING_HDMI (2 << 10) #define HDMI_MODE_SELECT_HDMI (1 << 9) /* HDMI only */ #define HDMI_MODE_SELECT_DVI (0 << 9) /* HDMI only */ -#define SDVO_COLOR_RANGE_16_235 (1 << 8) /* HDMI only */ +#define HDMI_COLOR_RANGE_16_235 (1 << 8) /* HDMI only */ #define SDVO_AUDIO_ENABLE (1 << 6) /* VSYNC/HSYNC bits new with 965, default is to be set */ #define SDVO_VSYNC_ACTIVE_HIGH (1 << 4) #define SDVO_HSYNC_ACTIVE_HIGH (1 << 3) /* Gen 5 (IBX) SDVO/HDMI bits: */ -#define COLOR_FORMAT_12bpc (3 << 26) /* HDMI only */ +#define HDMI_COLOR_FORMAT_12bpc (3 << 26) /* HDMI only */ #define SDVOB_HOTPLUG_ENABLE (1 << 23) /* SDVO only */ /* Gen 6 (CPT) SDVO/HDMI bits: */ diff --git a/drivers/gpu/drm/i915/intel_hdmi.c b/drivers/gpu/drm/i915/intel_hdmi.c index 0b42ba31d402..4d222ec58b81 100644 --- a/drivers/gpu/drm/i915/intel_hdmi.c +++ b/drivers/gpu/drm/i915/intel_hdmi.c @@ -609,9 +609,9 @@ static void intel_hdmi_mode_set(struct drm_encoder *encoder, hdmi_val |= SDVO_HSYNC_ACTIVE_HIGH; if (intel_crtc->bpp > 24) - hdmi_val |= COLOR_FORMAT_12bpc; + hdmi_val |= HDMI_COLOR_FORMAT_12bpc; else - hdmi_val |= COLOR_FORMAT_8bpc; + hdmi_val |= SDVO_COLOR_FORMAT_8bpc; /* Required on CPT */ if (intel_hdmi->has_hdmi_sink && HAS_PCH_CPT(dev)) @@ -778,7 +778,7 @@ bool intel_hdmi_mode_fixup(struct drm_encoder *encoder, /* 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; + intel_hdmi->color_range = HDMI_COLOR_RANGE_16_235; else intel_hdmi->color_range = 0; } @@ -941,7 +941,7 @@ intel_hdmi_set_property(struct drm_connector *connector, break; case INTEL_BROADCAST_RGB_LIMITED: intel_hdmi->color_range_auto = false; - intel_hdmi->color_range = SDVO_COLOR_RANGE_16_235; + intel_hdmi->color_range = HDMI_COLOR_RANGE_16_235; break; default: return -EINVAL; diff --git a/drivers/gpu/drm/i915/intel_sdvo.c b/drivers/gpu/drm/i915/intel_sdvo.c index eef073114f7a..63dcb760b004 100644 --- a/drivers/gpu/drm/i915/intel_sdvo.c +++ b/drivers/gpu/drm/i915/intel_sdvo.c @@ -1076,9 +1076,11 @@ static bool intel_sdvo_mode_fixup(struct drm_encoder *encoder, if (intel_sdvo->color_range_auto) { /* See CEA-861-E - 5.1 Default Encoding Parameters */ + /* FIXME: This bit is only valid when using TMDS encoding and 8 + * bit per color mode. */ if (intel_sdvo->has_hdmi_monitor && drm_mode_cea_vic(adjusted_mode) > 1) - intel_sdvo->color_range = SDVO_COLOR_RANGE_16_235; + intel_sdvo->color_range = HDMI_COLOR_RANGE_16_235; else intel_sdvo->color_range = 0; } @@ -1926,7 +1928,9 @@ intel_sdvo_set_property(struct drm_connector *connector, break; case INTEL_BROADCAST_RGB_LIMITED: intel_sdvo->color_range_auto = false; - intel_sdvo->color_range = SDVO_COLOR_RANGE_16_235; + /* FIXME: this bit is only valid when using TMDS + * encoding and 8 bit per color mode. */ + intel_sdvo->color_range = HDMI_COLOR_RANGE_16_235; break; default: return -EINVAL; From 8c123e549fd1533f371b7877d4c0458ba3a30b22 Mon Sep 17 00:00:00 2001 From: Ben Widawsky Date: Mon, 4 Mar 2013 17:00:29 -0800 Subject: [PATCH 36/79] drm/i915: Capture current context on error On error, this represents the state of the currently running context at the time it was loaded. Unfortunately, since we're hung and can't switch out the context this may not tell us too much about the most current state of the context, but does give clues about what has happened since loading. Thanks to recent doc updates, we have a little more confidence regarding what is actually in this memory, and perhaps it will help us gain more insight into certain bugs. AFAICT, the most interesting info is in the first page. To save space, we only capture the first page. In the future, we might want to dump more. Sample of the relevant part of error state: render ring --- HW Context = 0x01b20000 [0000] 00000000 1100105f 00002028 ffff0880 [0010] 0000209c feff4040 000020c0 efdf0080 [0020] 00002178 00000001 0000217c 00145855 [0030] 00002310 00000000 00002314 00000000 v2: Move error collection to the ring error code Change format of dump to not confuse intel_error_decode (Chris) Put the context error object with the others (Chris) Don't search bound_list instead of active_list (chris) v3: extract and flatten context recording (daniel) checkpatch related fixes for the copypasta in debugfs v4: bug in v3 (Daniel) - if ((ring->id == RCS) && error->ccid) + if ((ring->id != RCS) || !error->ccid) References: https://bugs.freedesktop.org/show_bug.cgi?id=55845 Reviewed-by (v2): Chris Wilson Signed-off-by: Ben Widawsky Cc: Daniel Vetter [danvet: Bikeshed away the redudant parenthese around ring->id != RCS] Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_debugfs.c | 17 +++++++++++++++++ drivers/gpu/drm/i915/i915_drv.h | 2 +- drivers/gpu/drm/i915/i915_irq.c | 23 +++++++++++++++++++++++ 3 files changed, 41 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/i915_debugfs.c b/drivers/gpu/drm/i915/i915_debugfs.c index 7c65ab83914a..c92ae7ff4718 100644 --- a/drivers/gpu/drm/i915/i915_debugfs.c +++ b/drivers/gpu/drm/i915/i915_debugfs.c @@ -772,6 +772,23 @@ static int i915_error_state(struct seq_file *m, void *unused) } } } + + obj = error->ring[i].ctx; + if (obj) { + seq_printf(m, "%s --- HW Context = 0x%08x\n", + dev_priv->ring[i].name, + obj->gtt_offset); + offset = 0; + for (elt = 0; elt < PAGE_SIZE/16; elt += 4) { + seq_printf(m, "[%04x] %08x %08x %08x %08x\n", + offset, + obj->pages[0][elt], + obj->pages[0][elt+1], + obj->pages[0][elt+2], + obj->pages[0][elt+3]); + offset += 16; + } + } } if (error->overlay) diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 669a535e82f3..ca6b215c090c 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -243,7 +243,7 @@ struct drm_i915_error_state { int page_count; u32 gtt_offset; u32 *pages[0]; - } *ringbuffer, *batchbuffer; + } *ringbuffer, *batchbuffer, *ctx; struct drm_i915_error_request { long jiffies; u32 seqno; diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c index 12561f2f7fd7..2139714b2a67 100644 --- a/drivers/gpu/drm/i915/i915_irq.c +++ b/drivers/gpu/drm/i915/i915_irq.c @@ -1242,6 +1242,26 @@ static void i915_record_ring_state(struct drm_device *dev, error->cpu_ring_tail[ring->id] = ring->tail; } + +static void i915_gem_record_active_context(struct intel_ring_buffer *ring, + struct drm_i915_error_state *error, + struct drm_i915_error_ring *ering) +{ + struct drm_i915_private *dev_priv = ring->dev->dev_private; + struct drm_i915_gem_object *obj; + + /* Currently render ring is the only HW context user */ + if (ring->id != RCS || !error->ccid) + return; + + list_for_each_entry(obj, &dev_priv->mm.bound_list, gtt_list) { + if ((error->ccid & PAGE_MASK) == obj->gtt_offset) { + ering->ctx = i915_error_object_create_sized(dev_priv, + obj, 1); + } + } +} + static void i915_gem_record_rings(struct drm_device *dev, struct drm_i915_error_state *error) { @@ -1259,6 +1279,9 @@ static void i915_gem_record_rings(struct drm_device *dev, error->ring[i].ringbuffer = i915_error_object_create(dev_priv, ring->obj); + + i915_gem_record_active_context(ring, error, &error->ring[i]); + count = 0; list_for_each_entry(request, &ring->request_list, list) count++; From 56c2912afc71bd3523167c5403d45ad3f7b33d22 Mon Sep 17 00:00:00 2001 From: Jesse Barnes Date: Sat, 2 Feb 2013 13:56:14 +0100 Subject: [PATCH 37/79] drm/i915: don't init LVDS on VLV Signed-off-by: Jesse Barnes Reviewed-by: Jani Nikula Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_lvds.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/gpu/drm/i915/intel_lvds.c b/drivers/gpu/drm/i915/intel_lvds.c index c7154bfa54cf..6b24fc57ff47 100644 --- a/drivers/gpu/drm/i915/intel_lvds.c +++ b/drivers/gpu/drm/i915/intel_lvds.c @@ -1023,6 +1023,9 @@ static bool intel_lvds_supported(struct drm_device *dev) if (HAS_PCH_SPLIT(dev)) return true; + if (IS_VALLEYVIEW(dev)) + return false; + /* Otherwise LVDS was only attached to mobile products, * except for the inglorious 830gm */ return IS_MOBILE(dev) && !IS_I830(dev); From 248ee3a803bf5754b86aef6af8d2a8f8104c8215 Mon Sep 17 00:00:00 2001 From: Jesse Barnes Date: Fri, 1 Mar 2013 13:14:13 -0800 Subject: [PATCH 38/79] drm/i915: VLV has force wake This was omitted from commit b7884eb45ec98c0d34c7f49005ae9d4b4b4e38f6 Author: Daniel Vetter Date: Mon Jun 4 11:18:15 2012 +0200 drm/i915: hold forcewake around ring hw init which introduced the ->has_force_wake flag. Note that this only enables the above w/a hack. Signed-off-by: Jesse Barnes [danvet: Put some interesting stuff into the empty commit message.] 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 b342749fcc87..1ebed9670ab9 100644 --- a/drivers/gpu/drm/i915/i915_drv.c +++ b/drivers/gpu/drm/i915/i915_drv.c @@ -275,6 +275,7 @@ static const struct intel_device_info intel_valleyview_m_info = { .has_blt_ring = 1, .is_valleyview = 1, .display_mmio_offset = VLV_DISPLAY_BASE, + .has_force_wake = 1, }; 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_blt_ring = 1, .is_valleyview = 1, .display_mmio_offset = VLV_DISPLAY_BASE, + .has_force_wake = 1, }; static const struct intel_device_info intel_haswell_d_info = { From 5d66d5b6beeed77b6058b2040af98dba04192900 Mon Sep 17 00:00:00 2001 From: Jesse Barnes Date: Fri, 1 Mar 2013 13:14:30 -0800 Subject: [PATCH 39/79] drm/i915/dp: don't use ILK paths on VLV Fix up a couple of places where we messed with PCH bits on VLV. Signed-off-by: Jesse Barnes Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_dp.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c index 0e2750cf85ef..843f7a502cf0 100644 --- a/drivers/gpu/drm/i915/intel_dp.c +++ b/drivers/gpu/drm/i915/intel_dp.c @@ -967,7 +967,7 @@ intel_dp_mode_set(struct drm_encoder *encoder, struct drm_display_mode *mode, intel_dp->DP |= DP_LINK_TRAIN_OFF_CPT; } - if (is_cpu_edp(intel_dp)) + if (is_cpu_edp(intel_dp) && !IS_VALLEYVIEW(dev)) ironlake_set_pll_edp(crtc, adjusted_mode->clock); } @@ -1331,7 +1331,7 @@ static bool intel_dp_get_hw_state(struct intel_encoder *encoder, if (!(tmp & DP_PORT_EN)) return false; - if (is_cpu_edp(intel_dp) && IS_GEN7(dev)) { + if (is_cpu_edp(intel_dp) && IS_GEN7(dev) && !IS_VALLEYVIEW(dev)) { *pipe = PORT_TO_PIPE_CPT(tmp); } else if (!HAS_PCH_CPT(dev) || is_cpu_edp(intel_dp)) { *pipe = PORT_TO_PIPE(tmp); From 086ddccec43be12fdf58f5ac6bbcd75d9d20d639 Mon Sep 17 00:00:00 2001 From: Jesse Barnes Date: Fri, 1 Mar 2013 14:08:29 -0800 Subject: [PATCH 40/79] drm/i915: use gen6 stolen check on VLV MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit It uses the same bit definitions. Signed-off-by: Jesse Barnes Reviewed-by: Ville Syrjälä 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 926a1e2dd234..2d7d3a94257b 100644 --- a/drivers/gpu/drm/i915/i915_gem_gtt.c +++ b/drivers/gpu/drm/i915/i915_gem_gtt.c @@ -752,7 +752,7 @@ static int gen6_gmch_probe(struct drm_device *dev, 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)) + if (IS_GEN7(dev) && !IS_VALLEYVIEW(dev)) *stolen = gen7_get_stolen_size(snb_gmch_ctl); else *stolen = gen6_get_stolen_size(snb_gmch_ctl); From 35aad75fd3afed550c42f5f5148d11c8c345f57d Mon Sep 17 00:00:00 2001 From: Jesse Barnes Date: Fri, 1 Mar 2013 13:14:31 -0800 Subject: [PATCH 41/79] drm/i915/dp: add pre-PCH eDP checking to DP detect for VLV Allows us to detect eDP panels that may not have the hotplug pin wired up. Signed-off-by: Jesse Barnes Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_dp.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c index 843f7a502cf0..3921d879a916 100644 --- a/drivers/gpu/drm/i915/intel_dp.c +++ b/drivers/gpu/drm/i915/intel_dp.c @@ -2258,6 +2258,16 @@ g4x_dp_detect(struct intel_dp *intel_dp) struct intel_digital_port *intel_dig_port = dp_to_dig_port(intel_dp); uint32_t bit; + /* Can't disconnect eDP, but you can close the lid... */ + if (is_edp(intel_dp)) { + enum drm_connector_status status; + + status = intel_panel_detect(dev); + if (status == connector_status_unknown) + status = connector_status_connected; + return status; + } + switch (intel_dig_port->port) { case PORT_B: bit = PORTB_HOTPLUG_LIVE_STATUS; From 5c67eeb6bf7eef062c835a64b501f3c926712fa5 Mon Sep 17 00:00:00 2001 From: Mihnea Dobrescu-Balaur Date: Sun, 10 Mar 2013 14:22:48 +0200 Subject: [PATCH 42/79] gpu: don't cast kzalloc() return value Signed-off-by: Mihnea Dobrescu-Balaur Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_sdvo.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/intel_sdvo.c b/drivers/gpu/drm/i915/intel_sdvo.c index 63dcb760b004..38b8511ca598 100644 --- a/drivers/gpu/drm/i915/intel_sdvo.c +++ b/drivers/gpu/drm/i915/intel_sdvo.c @@ -451,7 +451,7 @@ static bool intel_sdvo_write_cmd(struct intel_sdvo *intel_sdvo, u8 cmd, int i, ret = true; /* Would be simpler to allocate both in one go ? */ - buf = (u8 *)kzalloc(args_len * 2 + 2, GFP_KERNEL); + buf = kzalloc(args_len * 2 + 2, GFP_KERNEL); if (!buf) return false; From 647416f9eefe7699754b01b9fc82758fde83248c Mon Sep 17 00:00:00 2001 From: Kees Cook Date: Sun, 10 Mar 2013 14:10:06 -0700 Subject: [PATCH 43/79] drm/i915: use simple attribute in debugfs routines This replaces the manual read/write routines in debugfs with the common simple attribute helpers. Doing this gets rid of repeated copy/pasting of copy_from_user and value formatting code. Signed-off-by: Kees Cook Cc: Daniel Vetter [danvet: Squash in follow-up fix from Kees Cook to fix u64 divides on 32bit platforms.] Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_debugfs.c | 404 +++++++--------------------- 1 file changed, 103 insertions(+), 301 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_debugfs.c b/drivers/gpu/drm/i915/i915_debugfs.c index c92ae7ff4718..26487d18b023 100644 --- a/drivers/gpu/drm/i915/i915_debugfs.c +++ b/drivers/gpu/drm/i915/i915_debugfs.c @@ -866,76 +866,42 @@ static const struct file_operations i915_error_state_fops = { .release = i915_error_state_release, }; -static ssize_t -i915_next_seqno_read(struct file *filp, - char __user *ubuf, - size_t max, - loff_t *ppos) +static int +i915_next_seqno_get(void *data, u64 *val) { - struct drm_device *dev = filp->private_data; + struct drm_device *dev = data; drm_i915_private_t *dev_priv = dev->dev_private; - char buf[80]; - int len; int ret; ret = mutex_lock_interruptible(&dev->struct_mutex); if (ret) return ret; - len = snprintf(buf, sizeof(buf), - "next_seqno : 0x%x\n", - dev_priv->next_seqno); - + *val = dev_priv->next_seqno; mutex_unlock(&dev->struct_mutex); - if (len > sizeof(buf)) - len = sizeof(buf); - - return simple_read_from_buffer(ubuf, max, ppos, buf, len); + return 0; } -static ssize_t -i915_next_seqno_write(struct file *filp, - const char __user *ubuf, - size_t cnt, - loff_t *ppos) +static int +i915_next_seqno_set(void *data, u64 val) { - struct drm_device *dev = filp->private_data; - char buf[20]; - u32 val = 1; + struct drm_device *dev = data; int ret; - if (cnt > 0) { - if (cnt > sizeof(buf) - 1) - return -EINVAL; - - if (copy_from_user(buf, ubuf, cnt)) - return -EFAULT; - buf[cnt] = 0; - - ret = kstrtouint(buf, 0, &val); - if (ret < 0) - return ret; - } - ret = mutex_lock_interruptible(&dev->struct_mutex); if (ret) return ret; ret = i915_gem_set_seqno(dev, val); - mutex_unlock(&dev->struct_mutex); - return ret ?: cnt; + return ret; } -static const struct file_operations i915_next_seqno_fops = { - .owner = THIS_MODULE, - .open = simple_open, - .read = i915_next_seqno_read, - .write = i915_next_seqno_write, - .llseek = default_llseek, -}; +DEFINE_SIMPLE_ATTRIBUTE(i915_next_seqno_fops, + i915_next_seqno_get, i915_next_seqno_set, + "next_seqno : 0x%llx\n"); static int i915_rstdby_delays(struct seq_file *m, void *unused) { @@ -1697,105 +1663,51 @@ static int i915_dpio_info(struct seq_file *m, void *data) return 0; } -static ssize_t -i915_wedged_read(struct file *filp, - char __user *ubuf, - size_t max, - loff_t *ppos) +static int +i915_wedged_get(void *data, u64 *val) { - struct drm_device *dev = filp->private_data; + struct drm_device *dev = data; drm_i915_private_t *dev_priv = dev->dev_private; - char buf[80]; - int len; - len = snprintf(buf, sizeof(buf), - "wedged : %d\n", - atomic_read(&dev_priv->gpu_error.reset_counter)); + *val = atomic_read(&dev_priv->gpu_error.reset_counter); - if (len > sizeof(buf)) - len = sizeof(buf); - - return simple_read_from_buffer(ubuf, max, ppos, buf, len); + return 0; } -static ssize_t -i915_wedged_write(struct file *filp, - const char __user *ubuf, - size_t cnt, - loff_t *ppos) +static int +i915_wedged_set(void *data, u64 val) { - struct drm_device *dev = filp->private_data; - char buf[20]; - int val = 1; + struct drm_device *dev = data; - 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_INFO("Manually setting wedged to %d\n", val); + DRM_INFO("Manually setting wedged to %llu\n", val); i915_handle_error(dev, val); - return cnt; + return 0; } -static const struct file_operations i915_wedged_fops = { - .owner = THIS_MODULE, - .open = simple_open, - .read = i915_wedged_read, - .write = i915_wedged_write, - .llseek = default_llseek, -}; +DEFINE_SIMPLE_ATTRIBUTE(i915_wedged_fops, + i915_wedged_get, i915_wedged_set, + "wedged : %llu\n"); -static ssize_t -i915_ring_stop_read(struct file *filp, - char __user *ubuf, - size_t max, - loff_t *ppos) +static int +i915_ring_stop_get(void *data, u64 *val) { - struct drm_device *dev = filp->private_data; + struct drm_device *dev = data; drm_i915_private_t *dev_priv = dev->dev_private; - char buf[20]; - int len; - len = snprintf(buf, sizeof(buf), - "0x%08x\n", dev_priv->gpu_error.stop_rings); + *val = dev_priv->gpu_error.stop_rings; - if (len > sizeof(buf)) - len = sizeof(buf); - - return simple_read_from_buffer(ubuf, max, ppos, buf, len); + return 0; } -static ssize_t -i915_ring_stop_write(struct file *filp, - const char __user *ubuf, - size_t cnt, - loff_t *ppos) +static int +i915_ring_stop_set(void *data, u64 val) { - struct drm_device *dev = filp->private_data; + struct drm_device *dev = data; struct drm_i915_private *dev_priv = dev->dev_private; - char buf[20]; - int val = 0, ret; + int 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("Stopping rings 0x%08x\n", val); + DRM_DEBUG_DRIVER("Stopping rings 0x%08llx\n", val); ret = mutex_lock_interruptible(&dev->struct_mutex); if (ret) @@ -1804,16 +1716,12 @@ i915_ring_stop_write(struct file *filp, dev_priv->gpu_error.stop_rings = val; mutex_unlock(&dev->struct_mutex); - return cnt; + return 0; } -static const struct file_operations i915_ring_stop_fops = { - .owner = THIS_MODULE, - .open = simple_open, - .read = i915_ring_stop_read, - .write = i915_ring_stop_write, - .llseek = default_llseek, -}; +DEFINE_SIMPLE_ATTRIBUTE(i915_ring_stop_fops, + i915_ring_stop_get, i915_ring_stop_set, + "0x%08llx\n"); #define DROP_UNBOUND 0x1 #define DROP_BOUND 0x2 @@ -1823,46 +1731,23 @@ static const struct file_operations i915_ring_stop_fops = { 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) +static int +i915_drop_caches_get(void *data, u64 *val) { - char buf[20]; - int len; + *val = DROP_ALL; - 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); + return 0; } -static ssize_t -i915_drop_caches_write(struct file *filp, - const char __user *ubuf, - size_t cnt, - loff_t *ppos) +static int +i915_drop_caches_set(void *data, u64 val) { - struct drm_device *dev = filp->private_data; + struct drm_device *dev = data; struct drm_i915_private *dev_priv = dev->dev_private; struct drm_i915_gem_object *obj, *next; - char buf[20]; - int val = 0, ret; + int 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); + DRM_DEBUG_DRIVER("Dropping caches: 0x%08llx\n", val); /* No need to check and wait for gpu resets, only libdrm auto-restarts * on ioctls on -EAGAIN. */ @@ -1900,27 +1785,19 @@ i915_drop_caches_write(struct file *filp, unlock: mutex_unlock(&dev->struct_mutex); - return ret ?: cnt; + return ret; } -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, -}; +DEFINE_SIMPLE_ATTRIBUTE(i915_drop_caches_fops, + i915_drop_caches_get, i915_drop_caches_set, + "0x%08llx\n"); -static ssize_t -i915_max_freq_read(struct file *filp, - char __user *ubuf, - size_t max, - loff_t *ppos) +static int +i915_max_freq_get(void *data, u64 *val) { - struct drm_device *dev = filp->private_data; + struct drm_device *dev = data; drm_i915_private_t *dev_priv = dev->dev_private; - char buf[80]; - int len, ret; + int ret; if (!(IS_GEN6(dev) || IS_GEN7(dev))) return -ENODEV; @@ -1929,42 +1806,23 @@ i915_max_freq_read(struct file *filp, if (ret) return ret; - len = snprintf(buf, sizeof(buf), - "max freq: %d\n", dev_priv->rps.max_delay * GT_FREQUENCY_MULTIPLIER); + *val = dev_priv->rps.max_delay * GT_FREQUENCY_MULTIPLIER; mutex_unlock(&dev_priv->rps.hw_lock); - if (len > sizeof(buf)) - len = sizeof(buf); - - return simple_read_from_buffer(ubuf, max, ppos, buf, len); + return 0; } -static ssize_t -i915_max_freq_write(struct file *filp, - const char __user *ubuf, - size_t cnt, - loff_t *ppos) +static int +i915_max_freq_set(void *data, u64 val) { - struct drm_device *dev = filp->private_data; + struct drm_device *dev = data; struct drm_i915_private *dev_priv = dev->dev_private; - char buf[20]; - int val = 1, ret; + int ret; if (!(IS_GEN6(dev) || IS_GEN7(dev))) return -ENODEV; - 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("Manually setting max freq to %d\n", val); + DRM_DEBUG_DRIVER("Manually setting max freq to %llu\n", val); ret = mutex_lock_interruptible(&dev_priv->rps.hw_lock); if (ret) @@ -1973,30 +1831,24 @@ i915_max_freq_write(struct file *filp, /* * Turbo will still be enabled, but won't go above the set value. */ - dev_priv->rps.max_delay = val / GT_FREQUENCY_MULTIPLIER; - - gen6_set_rps(dev, val / GT_FREQUENCY_MULTIPLIER); + do_div(val, GT_FREQUENCY_MULTIPLIER); + dev_priv->rps.max_delay = val; + gen6_set_rps(dev, val); mutex_unlock(&dev_priv->rps.hw_lock); - return cnt; + return 0; } -static const struct file_operations i915_max_freq_fops = { - .owner = THIS_MODULE, - .open = simple_open, - .read = i915_max_freq_read, - .write = i915_max_freq_write, - .llseek = default_llseek, -}; +DEFINE_SIMPLE_ATTRIBUTE(i915_max_freq_fops, + i915_max_freq_get, i915_max_freq_set, + "max freq: %llu\n"); -static ssize_t -i915_min_freq_read(struct file *filp, char __user *ubuf, size_t max, - loff_t *ppos) +static int +i915_min_freq_get(void *data, u64 *val) { - struct drm_device *dev = filp->private_data; + struct drm_device *dev = data; drm_i915_private_t *dev_priv = dev->dev_private; - char buf[80]; - int len, ret; + int ret; if (!(IS_GEN6(dev) || IS_GEN7(dev))) return -ENODEV; @@ -2005,40 +1857,23 @@ i915_min_freq_read(struct file *filp, char __user *ubuf, size_t max, if (ret) return ret; - len = snprintf(buf, sizeof(buf), - "min freq: %d\n", dev_priv->rps.min_delay * GT_FREQUENCY_MULTIPLIER); + *val = dev_priv->rps.min_delay * GT_FREQUENCY_MULTIPLIER; mutex_unlock(&dev_priv->rps.hw_lock); - if (len > sizeof(buf)) - len = sizeof(buf); - - return simple_read_from_buffer(ubuf, max, ppos, buf, len); + return 0; } -static ssize_t -i915_min_freq_write(struct file *filp, const char __user *ubuf, size_t cnt, - loff_t *ppos) +static int +i915_min_freq_set(void *data, u64 val) { - struct drm_device *dev = filp->private_data; + struct drm_device *dev = data; struct drm_i915_private *dev_priv = dev->dev_private; - char buf[20]; - int val = 1, ret; + int ret; if (!(IS_GEN6(dev) || IS_GEN7(dev))) return -ENODEV; - 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("Manually setting min freq to %d\n", val); + DRM_DEBUG_DRIVER("Manually setting min freq to %llu\n", val); ret = mutex_lock_interruptible(&dev_priv->rps.hw_lock); if (ret) @@ -2047,33 +1882,25 @@ i915_min_freq_write(struct file *filp, const char __user *ubuf, size_t cnt, /* * Turbo will still be enabled, but won't go below the set value. */ - dev_priv->rps.min_delay = val / GT_FREQUENCY_MULTIPLIER; - - gen6_set_rps(dev, val / GT_FREQUENCY_MULTIPLIER); + do_div(val, GT_FREQUENCY_MULTIPLIER); + dev_priv->rps.min_delay = val; + gen6_set_rps(dev, val); mutex_unlock(&dev_priv->rps.hw_lock); - return cnt; + return 0; } -static const struct file_operations i915_min_freq_fops = { - .owner = THIS_MODULE, - .open = simple_open, - .read = i915_min_freq_read, - .write = i915_min_freq_write, - .llseek = default_llseek, -}; +DEFINE_SIMPLE_ATTRIBUTE(i915_min_freq_fops, + i915_min_freq_get, i915_min_freq_set, + "min freq: %llu\n"); -static ssize_t -i915_cache_sharing_read(struct file *filp, - char __user *ubuf, - size_t max, - loff_t *ppos) +static int +i915_cache_sharing_get(void *data, u64 *val) { - struct drm_device *dev = filp->private_data; + struct drm_device *dev = data; drm_i915_private_t *dev_priv = dev->dev_private; - char buf[80]; u32 snpcr; - int len, ret; + int ret; if (!(IS_GEN6(dev) || IS_GEN7(dev))) return -ENODEV; @@ -2085,46 +1912,25 @@ i915_cache_sharing_read(struct file *filp, snpcr = I915_READ(GEN6_MBCUNIT_SNPCR); mutex_unlock(&dev_priv->dev->struct_mutex); - len = snprintf(buf, sizeof(buf), - "%d\n", (snpcr & GEN6_MBC_SNPCR_MASK) >> - GEN6_MBC_SNPCR_SHIFT); + *val = (snpcr & GEN6_MBC_SNPCR_MASK) >> GEN6_MBC_SNPCR_SHIFT; - if (len > sizeof(buf)) - len = sizeof(buf); - - return simple_read_from_buffer(ubuf, max, ppos, buf, len); + return 0; } -static ssize_t -i915_cache_sharing_write(struct file *filp, - const char __user *ubuf, - size_t cnt, - loff_t *ppos) +static int +i915_cache_sharing_set(void *data, u64 val) { - struct drm_device *dev = filp->private_data; + struct drm_device *dev = data; struct drm_i915_private *dev_priv = dev->dev_private; - char buf[20]; u32 snpcr; - int val = 1; if (!(IS_GEN6(dev) || IS_GEN7(dev))) return -ENODEV; - 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); - } - - if (val < 0 || val > 3) + if (val > 3) return -EINVAL; - DRM_DEBUG_DRIVER("Manually setting uncore sharing to %d\n", val); + DRM_DEBUG_DRIVER("Manually setting uncore sharing to %llu\n", val); /* Update the cache sharing policy here as well */ snpcr = I915_READ(GEN6_MBCUNIT_SNPCR); @@ -2132,16 +1938,12 @@ i915_cache_sharing_write(struct file *filp, snpcr |= (val << GEN6_MBC_SNPCR_SHIFT); I915_WRITE(GEN6_MBCUNIT_SNPCR, snpcr); - return cnt; + return 0; } -static const struct file_operations i915_cache_sharing_fops = { - .owner = THIS_MODULE, - .open = simple_open, - .read = i915_cache_sharing_read, - .write = i915_cache_sharing_write, - .llseek = default_llseek, -}; +DEFINE_SIMPLE_ATTRIBUTE(i915_cache_sharing_fops, + i915_cache_sharing_get, i915_cache_sharing_set, + "%llu\n"); /* As the drm_debugfs_init() routines are called before dev->dev_private is * allocated we need to hook into the minor for release. */ From 3058753583c6a641bac188011b4d777adec916c9 Mon Sep 17 00:00:00 2001 From: Kees Cook Date: Mon, 11 Mar 2013 14:37:35 -0700 Subject: [PATCH 44/79] drm/i915: clarify reasoning for the access_ok call This clarifies the comment above the access_ok check so a missing VERIFY_READ doesn't alarm anyone. v2: - rewrote comment, thanks to Chris Wilson Signed-off-by: Kees Cook Cc: Daniel Vetter [danvet: add patch history log to commit message.] Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_gem_execbuffer.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/i915_gem_execbuffer.c b/drivers/gpu/drm/i915/i915_gem_execbuffer.c index 934396c5f048..ea963c32772d 100644 --- a/drivers/gpu/drm/i915/i915_gem_execbuffer.c +++ b/drivers/gpu/drm/i915/i915_gem_execbuffer.c @@ -747,7 +747,11 @@ validate_exec_list(struct drm_i915_gem_exec_object2 *exec, length = exec[i].relocation_count * sizeof(struct drm_i915_gem_relocation_entry); - /* we may also need to update the presumed offsets */ + /* + * We must check that the entire relocation array is safe + * to read, but since we may need to update the presumed + * offsets during execution, check for full write access. + */ if (!access_ok(VERIFY_WRITE, ptr, length)) return -EFAULT; From def27a58291f389d2c351ebf32ef5bb064587635 Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Tue, 12 Mar 2013 10:49:19 +0200 Subject: [PATCH 45/79] drm/i915: reduce power in the ilk rc6 enable error message Even if "power power" is good for grepping. Signed-off-by: Jani Nikula Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_pm.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c index 5479363083c6..be43f7107c99 100644 --- a/drivers/gpu/drm/i915/intel_pm.c +++ b/drivers/gpu/drm/i915/intel_pm.c @@ -2821,7 +2821,7 @@ static void ironlake_enable_rc6(struct drm_device *dev) ret = intel_ring_idle(ring); dev_priv->mm.interruptible = was_interruptible; if (ret) { - DRM_ERROR("failed to enable ironlake power power savings\n"); + DRM_ERROR("failed to enable ironlake power savings\n"); ironlake_teardown_rc6(dev); return; } From 2831d8427cace563767cb802de05db28c4c6f894 Mon Sep 17 00:00:00 2001 From: Paulo Zanoni Date: Wed, 6 Mar 2013 20:03:09 -0300 Subject: [PATCH 46/79] drm/i915: disable sound first on intel_disable_ddi Our mode set sequence documentation says audio must be disabled first. Signed-off-by: Paulo Zanoni Reviewed-by: Ben Widawsky [danvet: Resolve conflict since the first patch in this series isn't applied yet. Also bikeshed commit message as suggested by Ben.] Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_ddi.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_ddi.c b/drivers/gpu/drm/i915/intel_ddi.c index 56bb7cb78263..b49df7d9d235 100644 --- a/drivers/gpu/drm/i915/intel_ddi.c +++ b/drivers/gpu/drm/i915/intel_ddi.c @@ -1341,15 +1341,15 @@ static void intel_disable_ddi(struct intel_encoder *intel_encoder) struct drm_i915_private *dev_priv = dev->dev_private; uint32_t tmp; + 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); + 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) From a18c4c3d8fd5c0abe955b85a41f50798f321618f Mon Sep 17 00:00:00 2001 From: Paulo Zanoni Date: Wed, 6 Mar 2013 20:03:12 -0300 Subject: [PATCH 47/79] drm/i915: capture the correct cursor registers on IVB MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This solves some "unclaimed register" messages when there's a GPU hang on Haswell. Signed-off-by: Paulo Zanoni Reviewed-by: Ben Widawsky [danvet: Add missing IS_VLV check as spotted by Ville Syrjälä.] 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 502cb28a46c9..1dc6c18f3970 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -9334,9 +9334,15 @@ intel_display_capture_error_state(struct drm_device *dev) for_each_pipe(i) { cpu_transcoder = intel_pipe_to_cpu_transcoder(dev_priv, i); - error->cursor[i].control = I915_READ(CURCNTR(i)); - error->cursor[i].position = I915_READ(CURPOS(i)); - error->cursor[i].base = I915_READ(CURBASE(i)); + if (INTEL_INFO(dev)->gen <= 6 || IS_VALLEYVIEW(dev)) { + error->cursor[i].control = I915_READ(CURCNTR(i)); + error->cursor[i].position = I915_READ(CURPOS(i)); + error->cursor[i].base = I915_READ(CURBASE(i)); + } else { + error->cursor[i].control = I915_READ(CURCNTR_IVB(i)); + error->cursor[i].position = I915_READ(CURPOS_IVB(i)); + error->cursor[i].base = I915_READ(CURBASE_IVB(i)); + } error->plane[i].control = I915_READ(DSPCNTR(i)); error->plane[i].stride = I915_READ(DSPSTRIDE(i)); From 51889b35224cb05b5a9d187f3ebf872653ae06d2 Mon Sep 17 00:00:00 2001 From: Paulo Zanoni Date: Wed, 6 Mar 2013 20:03:13 -0300 Subject: [PATCH 48/79] drm/i915: there's no DSPSIZE register on gen4+ So don't read it when capturing the error state. This solves some "unclaimed register" messages on Haswell when we hang the GPU. Signed-off-by: Paulo Zanoni Reviewed-by: Ben Widawsky Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_display.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 1dc6c18f3970..1e706769de66 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -9346,7 +9346,8 @@ intel_display_capture_error_state(struct drm_device *dev) error->plane[i].control = I915_READ(DSPCNTR(i)); error->plane[i].stride = I915_READ(DSPSTRIDE(i)); - error->plane[i].size = I915_READ(DSPSIZE(i)); + if (INTEL_INFO(dev)->gen <= 3) + error->plane[i].size = I915_READ(DSPSIZE(i)); error->plane[i].pos = I915_READ(DSPPOS(i)); error->plane[i].addr = I915_READ(DSPADDR(i)); if (INTEL_INFO(dev)->gen >= 4) { @@ -9390,7 +9391,8 @@ intel_display_print_error_state(struct seq_file *m, seq_printf(m, "Plane [%d]:\n", i); seq_printf(m, " CNTR: %08x\n", error->plane[i].control); seq_printf(m, " STRIDE: %08x\n", error->plane[i].stride); - seq_printf(m, " SIZE: %08x\n", error->plane[i].size); + if (INTEL_INFO(dev)->gen <= 3) + seq_printf(m, " SIZE: %08x\n", error->plane[i].size); seq_printf(m, " POS: %08x\n", error->plane[i].pos); seq_printf(m, " ADDR: %08x\n", error->plane[i].addr); if (INTEL_INFO(dev)->gen >= 4) { From ca291363ccc7c0e9b337fe3b46f732247238537e Mon Sep 17 00:00:00 2001 From: Paulo Zanoni Date: Wed, 6 Mar 2013 20:03:14 -0300 Subject: [PATCH 49/79] drm/i915: there's no DSPADDR register on Haswell So don't read it when we hang the GPU. This solves "unclaimed register" messages. Signed-off-by: Paulo Zanoni Reviewed-by: Ben Widawsky [danvet: Future-proof by adding a gen >= 7 check in addition to the !IS_HSW check from Paulo's original patch, suggested by Ben.] Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_display.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 1e706769de66..630a96770043 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -9349,7 +9349,8 @@ intel_display_capture_error_state(struct drm_device *dev) if (INTEL_INFO(dev)->gen <= 3) error->plane[i].size = I915_READ(DSPSIZE(i)); error->plane[i].pos = I915_READ(DSPPOS(i)); - error->plane[i].addr = I915_READ(DSPADDR(i)); + if (INTEL_INFO(dev)->gen <= 7 && !IS_HASWELL(dev)) + error->plane[i].addr = I915_READ(DSPADDR(i)); if (INTEL_INFO(dev)->gen >= 4) { error->plane[i].surface = I915_READ(DSPSURF(i)); error->plane[i].tile_offset = I915_READ(DSPTILEOFF(i)); @@ -9394,7 +9395,8 @@ intel_display_print_error_state(struct seq_file *m, if (INTEL_INFO(dev)->gen <= 3) seq_printf(m, " SIZE: %08x\n", error->plane[i].size); seq_printf(m, " POS: %08x\n", error->plane[i].pos); - seq_printf(m, " ADDR: %08x\n", error->plane[i].addr); + if (!IS_HASWELL(dev)) + seq_printf(m, " ADDR: %08x\n", error->plane[i].addr); if (INTEL_INFO(dev)->gen >= 4) { seq_printf(m, " SURF: %08x\n", error->plane[i].surface); seq_printf(m, " TILEOFF: %08x\n", error->plane[i].tile_offset); From 86d52df633869b54a6f0b9a8f088be9c89a42c3d Mon Sep 17 00:00:00 2001 From: Paulo Zanoni Date: Wed, 6 Mar 2013 20:03:18 -0300 Subject: [PATCH 50/79] drm/i915: add HAS_POWER_WELL We're starting to add many IS_HASWELL checks for the power well code, so add a HAS_POWER_WELL macro to properly document that we're checking for hardware that has the power down well. Signed-off-by: Paulo Zanoni [danvet: Resolve conflicts since some converted code was added by not-yet merged patches.] Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_drv.h | 1 + drivers/gpu/drm/i915/intel_pm.c | 4 ++-- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index ca6b215c090c..71f285c56f1e 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -1339,6 +1339,7 @@ struct drm_i915_file_private { #define HAS_PIPE_CONTROL(dev) (INTEL_INFO(dev)->gen >= 5) #define HAS_DDI(dev) (IS_HASWELL(dev)) +#define HAS_POWER_WELL(dev) (IS_HASWELL(dev)) #define INTEL_PCH_DEVICE_ID_MASK 0xff00 #define INTEL_PCH_IBX_DEVICE_ID_TYPE 0x3b00 diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c index be43f7107c99..44a23b9b8e53 100644 --- a/drivers/gpu/drm/i915/intel_pm.c +++ b/drivers/gpu/drm/i915/intel_pm.c @@ -4076,7 +4076,7 @@ void intel_set_power_well(struct drm_device *dev, bool enable) bool is_enabled, enable_requested; uint32_t tmp; - if (!IS_HASWELL(dev)) + if (!HAS_POWER_WELL(dev)) return; tmp = I915_READ(HSW_PWR_WELL_DRIVER); @@ -4111,7 +4111,7 @@ void intel_init_power_well(struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; - if (!IS_HASWELL(dev)) + if (!HAS_POWER_WELL(dev)) return; /* For now, we need the power well to be always enabled. */ From 311e359c0bcbcfa6d71a56407477f2ec9c28c2d5 Mon Sep 17 00:00:00 2001 From: Paulo Zanoni Date: Wed, 6 Mar 2013 20:03:19 -0300 Subject: [PATCH 51/79] drm/i915: reorganize intel_lvds_supported Now it returns false for all platforms unless they're explicitly listed on the function. There should be no real difference, except for the fact that it now returns false on Haswell. Signed-off-by: Paulo Zanoni Reviewed-by: Ben Widawsky Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_lvds.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_lvds.c b/drivers/gpu/drm/i915/intel_lvds.c index 6b24fc57ff47..53bd5fd84028 100644 --- a/drivers/gpu/drm/i915/intel_lvds.c +++ b/drivers/gpu/drm/i915/intel_lvds.c @@ -1020,15 +1020,15 @@ static bool intel_lvds_supported(struct drm_device *dev) { /* With the introduction of the PCH we gained a dedicated * LVDS presence pin, use it. */ - if (HAS_PCH_SPLIT(dev)) + if (HAS_PCH_IBX(dev) || HAS_PCH_CPT(dev)) return true; - if (IS_VALLEYVIEW(dev)) - return false; - /* Otherwise LVDS was only attached to mobile products, * except for the inglorious 830gm */ - return IS_MOBILE(dev) && !IS_I830(dev); + if (INTEL_INFO(dev)->gen <= 4 && IS_MOBILE(dev) && !IS_I830(dev)) + return true; + + return false; } /** From 4deb88a6996268f44b91015779cfea81fd9fd8dd Mon Sep 17 00:00:00 2001 From: Paulo Zanoni Date: Wed, 6 Mar 2013 20:03:20 -0300 Subject: [PATCH 52/79] drm/i915: don't save/restore PCH_LVDS on LPT Because the register does not exist on LPT. The interesting fact is that reading/writing PCH_LVDS on LPT does *not* give us "unclaimed register" messages, but the register value is always 0. Signed-off-by: Paulo Zanoni Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_suspend.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_suspend.c b/drivers/gpu/drm/i915/i915_suspend.c index c1e02b040a34..41f0fdecfbdc 100644 --- a/drivers/gpu/drm/i915/i915_suspend.c +++ b/drivers/gpu/drm/i915/i915_suspend.c @@ -209,7 +209,8 @@ static void i915_save_display(struct drm_device *dev) dev_priv->regfile.saveBLC_PWM_CTL2 = I915_READ(BLC_PWM_PCH_CTL2); dev_priv->regfile.saveBLC_CPU_PWM_CTL = I915_READ(BLC_PWM_CPU_CTL); dev_priv->regfile.saveBLC_CPU_PWM_CTL2 = I915_READ(BLC_PWM_CPU_CTL2); - dev_priv->regfile.saveLVDS = I915_READ(PCH_LVDS); + if (HAS_PCH_IBX(dev) || HAS_PCH_CPT(dev)) + dev_priv->regfile.saveLVDS = I915_READ(PCH_LVDS); } else { dev_priv->regfile.savePP_CONTROL = I915_READ(PP_CONTROL); dev_priv->regfile.savePFIT_PGM_RATIOS = I915_READ(PFIT_PGM_RATIOS); @@ -271,9 +272,9 @@ static void i915_restore_display(struct drm_device *dev) if (drm_core_check_feature(dev, DRIVER_MODESET)) mask = ~LVDS_PORT_EN; - if (HAS_PCH_SPLIT(dev)) { + if (HAS_PCH_IBX(dev) || HAS_PCH_CPT(dev)) I915_WRITE(PCH_LVDS, dev_priv->regfile.saveLVDS & mask); - } else if (IS_MOBILE(dev) && !IS_I830(dev)) + else if (INTEL_INFO(dev)->gen <= 4 && IS_MOBILE(dev) && !IS_I830(dev)) I915_WRITE(LVDS, dev_priv->regfile.saveLVDS & mask); if (!IS_I830(dev) && !IS_845G(dev) && !HAS_PCH_SPLIT(dev)) From 5d83d2947ea8db7362942538772b6f9208f09c0e Mon Sep 17 00:00:00 2001 From: Paulo Zanoni Date: Wed, 6 Mar 2013 20:03:22 -0300 Subject: [PATCH 53/79] drm/i915: add missing space in error message To avoid this: [ 256.798060] [drm] capturing error event; look for more information in/sys/kernel/debug/dri/0/i915_error_state Ben Widawsky identified that this regression has been introduced in commit 2f86f1916504525a6fdd6b412374b4ebf1102cbe Author: Ben Widawsky Date: Mon Jan 28 15:32:15 2013 -0800 drm/i915: Error state should print /sys/kernel/debug ... [danvet: split up long line.] <----- he did it Signed-off-by: Daniel Vetter Signed-off-by: Paulo Zanoni Reviewed-by: Ben Widawsky [danvet: Pimp commit message with the regression note. Also, order more brown paper bags, I've run out.] Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_irq.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c index 2139714b2a67..39621e50ca5e 100644 --- a/drivers/gpu/drm/i915/i915_irq.c +++ b/drivers/gpu/drm/i915/i915_irq.c @@ -1337,7 +1337,7 @@ static void i915_capture_error_state(struct drm_device *dev) return; } - DRM_INFO("capturing error event; look for more information in" + DRM_INFO("capturing error event; look for more information in " "/sys/kernel/debug/dri/%d/i915_error_state\n", dev->primary->index); From a24a11e6b4e96bca817f854e0ffcce75d3eddd13 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Thu, 14 Mar 2013 17:52:05 +0200 Subject: [PATCH 54/79] drm/i915: Resurrect ring kicking for semaphores, selectively Once we thought we got semaphores working, we disabled kicking the ring if hangcheck fired whilst waiting upon a ring as it was doing more harm than good: commit 4e0e90dcb8a7df1229c69e30abebb59b0b3c2a1f Author: Daniel Vetter Date: Wed Dec 14 13:56:58 2011 +0100 drm/i915: kicking rings stuck on semaphores considered harmful However, life is never that easy and semaphores are still causing problems whereby the value written by one ring (bcs) is not being propagated to the waiter (rcs). Thus the waiter never wakes up and we declare the GPU hung, which often has unfortunate consequences, even if we successfully reset the GPU. But the GPU is idle as it has completed the work, just didn't notify its clients. So we can detect the incomplete wait during hang check and probe the target ring to see if has indeed emitted the breadcrumb seqno following the work and then and only then kick the waiter. Based on a suggestion by Ben Widawsky. v2: cross-check wait with iphdr. fix signaller calculation. References: https://bugs.freedesktop.org/show_bug.cgi?id=54226 Signed-off-by: Chris Wilson Signed-off-by: Mika Kuoppala Cc: Daniel Vetter Cc: Ben Widawsky Acked-by: Ben Widawsky Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_irq.c | 40 +++++++++++++++++++++++++++++++++ 1 file changed, 40 insertions(+) diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c index 39621e50ca5e..63abf2fa1fa4 100644 --- a/drivers/gpu/drm/i915/i915_irq.c +++ b/drivers/gpu/drm/i915/i915_irq.c @@ -1787,6 +1787,37 @@ static bool i915_hangcheck_ring_idle(struct intel_ring_buffer *ring, bool *err) return false; } +static bool semaphore_passed(struct intel_ring_buffer *ring) +{ + struct drm_i915_private *dev_priv = ring->dev->dev_private; + u32 acthd = intel_ring_get_active_head(ring) & HEAD_ADDR; + struct intel_ring_buffer *signaller; + u32 cmd, ipehr, acthd_min; + + ipehr = I915_READ(RING_IPEHR(ring->mmio_base)); + if ((ipehr & ~(0x3 << 16)) != + (MI_SEMAPHORE_MBOX | MI_SEMAPHORE_COMPARE | MI_SEMAPHORE_REGISTER)) + return false; + + /* ACTHD is likely pointing to the dword after the actual command, + * so scan backwards until we find the MBOX. + */ + acthd_min = max((int)acthd - 3 * 4, 0); + do { + cmd = ioread32(ring->virtual_start + acthd); + if (cmd == ipehr) + break; + + acthd -= 4; + if (acthd < acthd_min) + return false; + } while (1); + + signaller = &dev_priv->ring[(ring->id + (((ipehr >> 17) & 1) + 1)) % 3]; + return i915_seqno_passed(signaller->get_seqno(signaller, false), + ioread32(ring->virtual_start+acthd+4)+1); +} + static bool kick_ring(struct intel_ring_buffer *ring) { struct drm_device *dev = ring->dev; @@ -1798,6 +1829,15 @@ static bool kick_ring(struct intel_ring_buffer *ring) I915_WRITE_CTL(ring, tmp); return true; } + + if (INTEL_INFO(dev)->gen >= 6 && + tmp & RING_WAIT_SEMAPHORE && + semaphore_passed(ring)) { + DRM_ERROR("Kicking stuck semaphore on %s\n", + ring->name); + I915_WRITE_CTL(ring, tmp); + return true; + } return false; } From cf144969d54da1476e2b80dd632952a2f93c6b34 Mon Sep 17 00:00:00 2001 From: Ben Widawsky Date: Wed, 13 Mar 2013 17:21:05 -0700 Subject: [PATCH 55/79] drm/i915: Remove unused file arg from execbuf Signed-off-by: Ben Widawsky Acked-by: Chris Wilson Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_gem_execbuffer.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_gem_execbuffer.c b/drivers/gpu/drm/i915/i915_gem_execbuffer.c index ea963c32772d..87948a467641 100644 --- a/drivers/gpu/drm/i915/i915_gem_execbuffer.c +++ b/drivers/gpu/drm/i915/i915_gem_execbuffer.c @@ -475,7 +475,6 @@ 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, bool *need_relocs) { @@ -663,7 +662,7 @@ i915_gem_execbuffer_relocate_slow(struct drm_device *dev, goto err; need_relocs = (args->flags & I915_EXEC_NO_RELOC) == 0; - ret = i915_gem_execbuffer_reserve(ring, file, &eb->objects, &need_relocs); + ret = i915_gem_execbuffer_reserve(ring, &eb->objects, &need_relocs); if (ret) goto err; @@ -984,7 +983,7 @@ i915_gem_do_execbuffer(struct drm_device *dev, void *data, /* Move the objects en-masse into the GTT, evicting if necessary. */ need_relocs = (args->flags & I915_EXEC_NO_RELOC) == 0; - ret = i915_gem_execbuffer_reserve(ring, file, &eb->objects, &need_relocs); + ret = i915_gem_execbuffer_reserve(ring, &eb->objects, &need_relocs); if (ret) goto err; From 41fda596826c5db206f67ce5d639f65a19924a99 Mon Sep 17 00:00:00 2001 From: Ben Widawsky Date: Wed, 13 Mar 2013 17:21:06 -0700 Subject: [PATCH 56/79] drm/i915: Remove unneeded dev argument Signed-off-by: Ben Widawsky Acked-by: Chris Wilson Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_gem_execbuffer.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_gem_execbuffer.c b/drivers/gpu/drm/i915/i915_gem_execbuffer.c index 87948a467641..983083976dd8 100644 --- a/drivers/gpu/drm/i915/i915_gem_execbuffer.c +++ b/drivers/gpu/drm/i915/i915_gem_execbuffer.c @@ -359,8 +359,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) +i915_gem_execbuffer_relocate(struct eb_objects *eb) { struct drm_i915_gem_object *obj; int ret = 0; @@ -989,7 +988,7 @@ i915_gem_do_execbuffer(struct drm_device *dev, void *data, /* The objects are in their final locations, apply the relocations. */ if (need_relocs) - ret = i915_gem_execbuffer_relocate(dev, eb); + ret = i915_gem_execbuffer_relocate(eb); if (ret) { if (ret == -EFAULT) { ret = i915_gem_execbuffer_relocate_slow(dev, args, file, ring, From d62b4892f3d9f7dd2002e5309be10719d6805b0f Mon Sep 17 00:00:00 2001 From: Jesse Barnes Date: Fri, 8 Mar 2013 10:45:53 -0800 Subject: [PATCH 57/79] drm/i915: allow force wake at init time on VLV v2 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We need to set the 'allow force wake' bit to enable forcewake handling later on. v2: split from clock gating patch (Jani) check for allowwakeack (Ville) Signed-off-by: Jesse Barnes Reviewed-by: Ville Syrjälä Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_gem.c | 9 +++++++++ drivers/gpu/drm/i915/i915_reg.h | 2 ++ 2 files changed, 11 insertions(+) diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index 1417fc6c28ee..d554b2171df0 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -4010,7 +4010,16 @@ int i915_gem_init(struct drm_device *dev) int ret; mutex_lock(&dev->struct_mutex); + + if (IS_VALLEYVIEW(dev)) { + /* VLVA0 (potential hack), BIOS isn't actually waking us */ + I915_WRITE(VLV_GTLC_WAKE_CTRL, 1); + if (wait_for((I915_READ(VLV_GTLC_PW_STATUS) & 1) == 1, 10)) + DRM_DEBUG_DRIVER("allow wake ack timed out\n"); + } + i915_gem_init_global_gtt(dev); + ret = i915_gem_init_hw(dev); mutex_unlock(&dev->struct_mutex); if (ret) { diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index 4cf3eceb5153..f187b60739ed 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -4150,6 +4150,8 @@ #define FORCEWAKE_ACK_VLV 0x1300b4 #define FORCEWAKE_ACK_HSW 0x130044 #define FORCEWAKE_ACK 0x130090 +#define VLV_GTLC_WAKE_CTRL 0x130090 +#define VLV_GTLC_PW_STATUS 0x130094 #define FORCEWAKE_MT 0xa188 /* multi-threaded */ #define FORCEWAKE_KERNEL 0x1 #define FORCEWAKE_USER 0x2 From f5ddf69736fb328800ccd1a06fe69ad2e830adbe Mon Sep 17 00:00:00 2001 From: Imre Deak Date: Mon, 18 Feb 2013 19:28:01 +0200 Subject: [PATCH 58/79] drm: handle compact dma scatter lists in drm_clflush_sg() So far the assumption was that each scatter list entry contains a single page. This might not hold in the future, when we'll introduce compact scatter lists, so prepare for this here. Reference: http://www.spinics.net/lists/dri-devel/msg33917.html Signed-off-by: Imre Deak Acked-by: Dave Airlie Signed-off-by: Daniel Vetter --- drivers/gpu/drm/drm_cache.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/drm_cache.c b/drivers/gpu/drm/drm_cache.c index a575cb2e6bdb..bc8edbeca3fd 100644 --- a/drivers/gpu/drm/drm_cache.c +++ b/drivers/gpu/drm/drm_cache.c @@ -105,12 +105,11 @@ drm_clflush_sg(struct sg_table *st) { #if defined(CONFIG_X86) if (cpu_has_clflush) { - struct scatterlist *sg; - int i; + struct sg_page_iter sg_iter; mb(); - for_each_sg(st->sgl, sg, st->nents, i) - drm_clflush_page(sg_page(sg)); + for_each_sg_page(st->sgl, &sg_iter, st->nents, 0) + drm_clflush_page(sg_iter.page); mb(); return; From 5bd4687e57bbacec20930f580d025aee9fa1f4d8 Mon Sep 17 00:00:00 2001 From: Imre Deak Date: Fri, 22 Mar 2013 23:10:44 +0200 Subject: [PATCH 59/79] drm/i915: set dummy page for stolen objects This is needed since currently sg_for_each_page assumes that we have a valid page in each sg item. It is only a real problem for CONFIG_SPARSEMEM where the page is dereferenced, in other cases the iterator works ok with an invalid page pointer. We can remove this workaround when we have fixed sg_page_iter to work on scatterlists without backing pages. Signed-off-by: Imre Deak --- drivers/gpu/drm/i915/i915_gem_stolen.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_gem_stolen.c b/drivers/gpu/drm/i915/i915_gem_stolen.c index 69d97cbac13c..efaaba5c4194 100644 --- a/drivers/gpu/drm/i915/i915_gem_stolen.c +++ b/drivers/gpu/drm/i915/i915_gem_stolen.c @@ -222,8 +222,8 @@ i915_pages_create_for_stolen(struct drm_device *dev, } sg = st->sgl; - sg->offset = offset; - sg->length = size; + /* we set the dummy page here only to make for_each_sg_page work */ + sg_set_page(sg, dev_priv->gtt.scratch_page, size, offset); sg_dma_address(sg) = (dma_addr_t)dev_priv->mm.stolen_base + offset; sg_dma_len(sg) = size; From 67d5a50c0480d5d41e0423e6fa55984f9fd3381e Mon Sep 17 00:00:00 2001 From: Imre Deak Date: Mon, 18 Feb 2013 19:28:02 +0200 Subject: [PATCH 60/79] drm/i915: handle walking compact dma scatter lists So far the assumption was that each dma scatter list entry contains only a single page. This might not hold in the future, when we'll introduce compact scatter lists, so prepare for this everywhere in the i915 code where we walk such a list. We'll fix the place _creating_ these lists separately in the next patch to help the reviewing/bisectability. Reference: http://www.spinics.net/lists/dri-devel/msg33917.html Signed-off-by: Imre Deak Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_drv.h | 15 +++++---------- drivers/gpu/drm/i915/i915_gem.c | 24 ++++++++---------------- drivers/gpu/drm/i915/i915_gem_dmabuf.c | 13 +++++++------ drivers/gpu/drm/i915/i915_gem_tiling.c | 18 ++++++++++-------- 4 files changed, 30 insertions(+), 40 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 71f285c56f1e..1246a31c0243 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -1528,17 +1528,12 @@ void i915_gem_lastclose(struct drm_device *dev); int __must_check i915_gem_object_get_pages(struct drm_i915_gem_object *obj); static inline struct page *i915_gem_object_get_page(struct drm_i915_gem_object *obj, int n) { - struct scatterlist *sg = obj->pages->sgl; - int nents = obj->pages->nents; - while (nents > SG_MAX_SINGLE_ALLOC) { - if (n < SG_MAX_SINGLE_ALLOC - 1) - break; + struct sg_page_iter sg_iter; - sg = sg_chain_ptr(sg + SG_MAX_SINGLE_ALLOC - 1); - n -= SG_MAX_SINGLE_ALLOC - 1; - nents -= SG_MAX_SINGLE_ALLOC - 1; - } - return sg_page(sg+n); + for_each_sg_page(obj->pages->sgl, &sg_iter, obj->pages->nents, n) + return sg_iter.page; + + return NULL; } static inline void i915_gem_object_pin_pages(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 30117dc52212..5cf6140354db 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -411,8 +411,7 @@ i915_gem_shmem_pread(struct drm_device *dev, int obj_do_bit17_swizzling, page_do_bit17_swizzling; int prefaulted = 0; int needs_clflush = 0; - struct scatterlist *sg; - int i; + struct sg_page_iter sg_iter; user_data = to_user_ptr(args->data_ptr); remain = args->size; @@ -441,11 +440,9 @@ i915_gem_shmem_pread(struct drm_device *dev, offset = args->offset; - for_each_sg(obj->pages->sgl, sg, obj->pages->nents, i) { - struct page *page; - - if (i < offset >> PAGE_SHIFT) - continue; + for_each_sg_page(obj->pages->sgl, &sg_iter, obj->pages->nents, + offset >> PAGE_SHIFT) { + struct page *page = sg_iter.page; if (remain <= 0) break; @@ -460,7 +457,6 @@ i915_gem_shmem_pread(struct drm_device *dev, if ((shmem_page_offset + page_length) > PAGE_SIZE) page_length = PAGE_SIZE - shmem_page_offset; - page = sg_page(sg); page_do_bit17_swizzling = obj_do_bit17_swizzling && (page_to_phys(page) & (1 << 17)) != 0; @@ -732,8 +728,7 @@ i915_gem_shmem_pwrite(struct drm_device *dev, int hit_slowpath = 0; int needs_clflush_after = 0; int needs_clflush_before = 0; - int i; - struct scatterlist *sg; + struct sg_page_iter sg_iter; user_data = to_user_ptr(args->data_ptr); remain = args->size; @@ -768,13 +763,11 @@ i915_gem_shmem_pwrite(struct drm_device *dev, offset = args->offset; obj->dirty = 1; - for_each_sg(obj->pages->sgl, sg, obj->pages->nents, i) { - struct page *page; + for_each_sg_page(obj->pages->sgl, &sg_iter, obj->pages->nents, + offset >> PAGE_SHIFT) { + struct page *page = sg_iter.page; int partial_cacheline_write; - if (i < offset >> PAGE_SHIFT) - continue; - if (remain <= 0) break; @@ -796,7 +789,6 @@ i915_gem_shmem_pwrite(struct drm_device *dev, ((shmem_page_offset | page_length) & (boot_cpu_data.x86_clflush_size - 1)); - page = sg_page(sg); page_do_bit17_swizzling = obj_do_bit17_swizzling && (page_to_phys(page) & (1 << 17)) != 0; diff --git a/drivers/gpu/drm/i915/i915_gem_dmabuf.c b/drivers/gpu/drm/i915/i915_gem_dmabuf.c index 6a5af6828624..898615d2d5e2 100644 --- a/drivers/gpu/drm/i915/i915_gem_dmabuf.c +++ b/drivers/gpu/drm/i915/i915_gem_dmabuf.c @@ -62,7 +62,7 @@ static struct sg_table *i915_gem_map_dma_buf(struct dma_buf_attachment *attachme src = obj->pages->sgl; dst = st->sgl; for (i = 0; i < obj->pages->nents; i++) { - sg_set_page(dst, sg_page(src), PAGE_SIZE, 0); + sg_set_page(dst, sg_page(src), src->length, 0); dst = sg_next(dst); src = sg_next(src); } @@ -105,7 +105,7 @@ static void *i915_gem_dmabuf_vmap(struct dma_buf *dma_buf) { struct drm_i915_gem_object *obj = dma_buf->priv; struct drm_device *dev = obj->base.dev; - struct scatterlist *sg; + struct sg_page_iter sg_iter; struct page **pages; int ret, i; @@ -124,14 +124,15 @@ static void *i915_gem_dmabuf_vmap(struct dma_buf *dma_buf) ret = -ENOMEM; - pages = drm_malloc_ab(obj->pages->nents, sizeof(struct page *)); + pages = drm_malloc_ab(obj->base.size >> PAGE_SHIFT, sizeof(*pages)); if (pages == NULL) goto error; - for_each_sg(obj->pages->sgl, sg, obj->pages->nents, i) - pages[i] = sg_page(sg); + i = 0; + for_each_sg_page(obj->pages->sgl, &sg_iter, obj->pages->nents, 0); + pages[i++] = sg_iter.page; - obj->dma_buf_vmapping = vmap(pages, obj->pages->nents, 0, PAGE_KERNEL); + obj->dma_buf_vmapping = vmap(pages, i, 0, PAGE_KERNEL); drm_free_large(pages); if (!obj->dma_buf_vmapping) diff --git a/drivers/gpu/drm/i915/i915_gem_tiling.c b/drivers/gpu/drm/i915/i915_gem_tiling.c index abcba2f5a788..f799708bcb85 100644 --- a/drivers/gpu/drm/i915/i915_gem_tiling.c +++ b/drivers/gpu/drm/i915/i915_gem_tiling.c @@ -473,28 +473,29 @@ i915_gem_swizzle_page(struct page *page) void i915_gem_object_do_bit_17_swizzle(struct drm_i915_gem_object *obj) { - struct scatterlist *sg; - int page_count = obj->base.size >> PAGE_SHIFT; + struct sg_page_iter sg_iter; int i; if (obj->bit_17 == NULL) return; - for_each_sg(obj->pages->sgl, sg, page_count, i) { - struct page *page = sg_page(sg); + i = 0; + for_each_sg_page(obj->pages->sgl, &sg_iter, obj->pages->nents, 0) { + struct page *page = sg_iter.page; char new_bit_17 = page_to_phys(page) >> 17; if ((new_bit_17 & 0x1) != (test_bit(i, obj->bit_17) != 0)) { i915_gem_swizzle_page(page); set_page_dirty(page); } + i++; } } void i915_gem_object_save_bit_17_swizzle(struct drm_i915_gem_object *obj) { - struct scatterlist *sg; + struct sg_page_iter sg_iter; int page_count = obj->base.size >> PAGE_SHIFT; int i; @@ -508,11 +509,12 @@ i915_gem_object_save_bit_17_swizzle(struct drm_i915_gem_object *obj) } } - for_each_sg(obj->pages->sgl, sg, page_count, i) { - struct page *page = sg_page(sg); - if (page_to_phys(page) & (1 << 17)) + i = 0; + for_each_sg_page(obj->pages->sgl, &sg_iter, obj->pages->nents, 0) { + if (page_to_phys(sg_iter.page) & (1 << 17)) __set_bit(i, obj->bit_17); else __clear_bit(i, obj->bit_17); + i++; } } From 90797e6d1ec0dfde6ba62a48b9ee3803887d6ed4 Mon Sep 17 00:00:00 2001 From: Imre Deak Date: Mon, 18 Feb 2013 19:28:03 +0200 Subject: [PATCH 61/79] drm/i915: create compact dma scatter lists for gem objects So far we created a sparse dma scatter list for gem objects, where each scatter list entry represented only a single page. In the future we'll have to handle compact scatter lists too where each entry can consist of multiple pages, for example for objects imported through PRIME. The previous patches have already fixed up all other places where the i915 driver _walked_ these lists. Here we have the corresponding fix to _create_ compact lists. It's not a performance or memory footprint improvement, but it helps to better exercise the new logic. Reference: http://www.spinics.net/lists/dri-devel/msg33917.html Signed-off-by: Imre Deak Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_gem.c | 31 ++++++++++++++++++++++--------- 1 file changed, 22 insertions(+), 9 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index 5cf6140354db..8a2cbee491a2 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -1625,9 +1625,8 @@ i915_gem_object_is_purgeable(struct drm_i915_gem_object *obj) static void i915_gem_object_put_pages_gtt(struct drm_i915_gem_object *obj) { - int page_count = obj->base.size / PAGE_SIZE; - struct scatterlist *sg; - int ret, i; + struct sg_page_iter sg_iter; + int ret; BUG_ON(obj->madv == __I915_MADV_PURGED); @@ -1647,8 +1646,8 @@ i915_gem_object_put_pages_gtt(struct drm_i915_gem_object *obj) if (obj->madv == I915_MADV_DONTNEED) obj->dirty = 0; - for_each_sg(obj->pages->sgl, sg, page_count, i) { - struct page *page = sg_page(sg); + for_each_sg_page(obj->pages->sgl, &sg_iter, obj->pages->nents, 0) { + struct page *page = sg_iter.page; if (obj->dirty) set_page_dirty(page); @@ -1749,7 +1748,9 @@ i915_gem_object_get_pages_gtt(struct drm_i915_gem_object *obj) struct address_space *mapping; struct sg_table *st; struct scatterlist *sg; + struct sg_page_iter sg_iter; struct page *page; + unsigned long last_pfn = 0; /* suppress gcc warning */ gfp_t gfp; /* Assert that the object is not currently in any GPU domain. As it @@ -1779,7 +1780,9 @@ i915_gem_object_get_pages_gtt(struct drm_i915_gem_object *obj) gfp = mapping_gfp_mask(mapping); gfp |= __GFP_NORETRY | __GFP_NOWARN | __GFP_NO_KSWAPD; gfp &= ~(__GFP_IO | __GFP_WAIT); - for_each_sg(st->sgl, sg, page_count, i) { + sg = st->sgl; + st->nents = 0; + for (i = 0; i < page_count; i++) { page = shmem_read_mapping_page_gfp(mapping, i, gfp); if (IS_ERR(page)) { i915_gem_purge(dev_priv, page_count); @@ -1802,9 +1805,18 @@ i915_gem_object_get_pages_gtt(struct drm_i915_gem_object *obj) gfp &= ~(__GFP_IO | __GFP_WAIT); } - sg_set_page(sg, page, PAGE_SIZE, 0); + if (!i || page_to_pfn(page) != last_pfn + 1) { + if (i) + sg = sg_next(sg); + st->nents++; + sg_set_page(sg, page, PAGE_SIZE, 0); + } else { + sg->length += PAGE_SIZE; + } + last_pfn = page_to_pfn(page); } + sg_mark_end(sg); obj->pages = st; if (i915_gem_object_needs_bit17_swizzle(obj)) @@ -1813,8 +1825,9 @@ i915_gem_object_get_pages_gtt(struct drm_i915_gem_object *obj) return 0; err_pages: - for_each_sg(st->sgl, sg, i, page_count) - page_cache_release(sg_page(sg)); + sg_mark_end(sg); + for_each_sg_page(st->sgl, &sg_iter, st->nents, 0) + page_cache_release(sg_iter.page); sg_free_table(st); kfree(st); return PTR_ERR(page); From 6e995e231a90ce7c5ce2a9eae23c8e22f4388db1 Mon Sep 17 00:00:00 2001 From: Imre Deak Date: Mon, 18 Feb 2013 19:28:04 +0200 Subject: [PATCH 62/79] drm/i915: use for_each_sg_page for setting up the gtt ptes The existing gtt setup code is correct - and so doesn't need to be fixed to handle compact dma scatter lists similarly to the previous patches. Still, take the for_each_sg_page macro into use, to get somewhat simpler code. Signed-off-by: Imre Deak Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_gem_gtt.c | 63 ++++++++++------------------- 1 file changed, 22 insertions(+), 41 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_gem_gtt.c b/drivers/gpu/drm/i915/i915_gem_gtt.c index 2d7d3a94257b..c0ccbe7b61bc 100644 --- a/drivers/gpu/drm/i915/i915_gem_gtt.c +++ b/drivers/gpu/drm/i915/i915_gem_gtt.c @@ -116,41 +116,26 @@ static void gen6_ppgtt_insert_entries(struct i915_hw_ppgtt *ppgtt, { 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; + unsigned act_pte = first_entry % I915_PPGTT_PT_ENTRIES; + struct sg_page_iter sg_iter; - /* init sg walking */ - sg = pages->sgl; - i = 0; - segment_len = sg_dma_len(sg) >> PAGE_SHIFT; - m = 0; + pt_vaddr = kmap_atomic(ppgtt->pt_pages[act_pd]); + for_each_sg_page(pages->sgl, &sg_iter, pages->nents, 0) { + dma_addr_t page_addr; - while (i < pages->nents) { - pt_vaddr = kmap_atomic(ppgtt->pt_pages[act_pd]); + page_addr = sg_dma_address(sg_iter.sg) + + (sg_iter.sg_pgoffset << PAGE_SHIFT); + pt_vaddr[act_pte] = gen6_pte_encode(ppgtt->dev, page_addr, + cache_level); + if (++act_pte == I915_PPGTT_PT_ENTRIES) { + kunmap_atomic(pt_vaddr); + act_pd++; + pt_vaddr = kmap_atomic(ppgtt->pt_pages[act_pd]); + act_pte = 0; - for (j = first_pte; j < I915_PPGTT_PT_ENTRIES; j++) { - page_addr = sg_dma_address(sg) + (m << PAGE_SHIFT); - pt_vaddr[j] = gen6_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++; } + kunmap_atomic(pt_vaddr); } static void gen6_ppgtt_cleanup(struct i915_hw_ppgtt *ppgtt) @@ -432,21 +417,17 @@ static void gen6_ggtt_insert_entries(struct drm_device *dev, enum i915_cache_level level) { struct drm_i915_private *dev_priv = dev->dev_private; - struct scatterlist *sg = st->sgl; gtt_pte_t __iomem *gtt_entries = (gtt_pte_t __iomem *)dev_priv->gtt.gsm + first_entry; - int unused, i = 0; - unsigned int len, m = 0; + int i = 0; + struct sg_page_iter sg_iter; dma_addr_t addr; - for_each_sg(st->sgl, sg, st->nents, unused) { - len = sg_dma_len(sg) >> PAGE_SHIFT; - for (m = 0; m < len; m++) { - addr = sg_dma_address(sg) + (m << PAGE_SHIFT); - iowrite32(gen6_pte_encode(dev, addr, level), - >t_entries[i]); - i++; - } + for_each_sg_page(st->sgl, &sg_iter, st->nents, 0) { + addr = sg_dma_address(sg_iter.sg) + + (sg_iter.sg_pgoffset << PAGE_SHIFT); + iowrite32(gen6_pte_encode(dev, addr, level), >t_entries[i]); + i++; } /* XXX: This serves as a posting read to make sure that the PTE has From dca25cb80065849e71e5c95a7fd74b0d67695bf3 Mon Sep 17 00:00:00 2001 From: Rahul Sharma Date: Mon, 28 Jan 2013 08:38:48 -0500 Subject: [PATCH 63/79] drm: modify pages_to_sg prime helper to create optimized SG table It fixes the issue arises due to passing 'nr_pages' in place of 'nents' to sg_alloc_table. When ARM_HAS_SG_CHAIN is disabled, it is causing failure in creating SG table for the buffers having more than 204 physical pages i.e. equal to SG_MAX_SINGLE_ALLOC. When using sg_alloc_table_from_pages interface, in place of sg_alloc_table, page list will be passes to get each contiguous section which is represented by a single entry in the table. For a Contiguous Buffer, number of entries should be equal to 1. Following check is causing the failure which is not applicable for Non-Contig buffers: if (WARN_ON_ONCE(nents > max_ents)) return -EINVAL; Above patch is well tested for EXYNOS4 and EXYNOS5 for with/wihtout IOMMU supprot. NOUVEAU and RADEON platforms also depends on drm_prime_pages_to_sg helper function. This set is base on "exynos-drm-fixes" branch at http://git.kernel.org/?p=linux/kernel/git/daeinki/drm-exynos.git Signed-off-by: Rahul Sharma Acked-by: Dave Airlie Reviewed-by: Aaron Plattner Tested-by: Aaron Plattner Signed-off-by: Daniel Vetter --- drivers/gpu/drm/drm_prime.c | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/drivers/gpu/drm/drm_prime.c b/drivers/gpu/drm/drm_prime.c index 366910ddcfcb..25d02187067e 100644 --- a/drivers/gpu/drm/drm_prime.c +++ b/drivers/gpu/drm/drm_prime.c @@ -401,21 +401,17 @@ int drm_prime_fd_to_handle_ioctl(struct drm_device *dev, void *data, struct sg_table *drm_prime_pages_to_sg(struct page **pages, int nr_pages) { struct sg_table *sg = NULL; - struct scatterlist *iter; - int i; int ret; sg = kmalloc(sizeof(struct sg_table), GFP_KERNEL); if (!sg) goto out; - ret = sg_alloc_table(sg, nr_pages, GFP_KERNEL); + ret = sg_alloc_table_from_pages(sg, pages, nr_pages, 0, + nr_pages << PAGE_SHIFT, GFP_KERNEL); if (ret) goto out; - for_each_sg(sg->sgl, iter, nr_pages, i) - sg_set_page(iter, pages[i], PAGE_SIZE, 0); - return sg; out: kfree(sg); From da6ecc5decf6243a93dd0ecae4a4a773bf21dcce Mon Sep 17 00:00:00 2001 From: Jesse Barnes Date: Fri, 8 Mar 2013 10:46:00 -0800 Subject: [PATCH 64/79] drm/i915: don't use plane pipe select on VLV MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Planes are fixed to pipes in VLV. Signed-off-by: Jesse Barnes Reviewed-by: Ville Syrjälä Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_display.c | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index f73fc3df2bf8..6953f88bf04d 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -1267,7 +1267,7 @@ static void assert_planes_disabled(struct drm_i915_private *dev_priv, int cur_pipe; /* Planes are fixed to pipes on ILK+ */ - if (HAS_PCH_SPLIT(dev_priv->dev)) { + if (HAS_PCH_SPLIT(dev_priv->dev) || IS_VALLEYVIEW(dev_priv->dev)) { reg = DSPCNTR(pipe); val = I915_READ(reg); WARN((val & DISPLAY_PLANE_ENABLE), @@ -4743,10 +4743,12 @@ static int i9xx_crtc_mode_set(struct drm_crtc *crtc, /* Set up the display plane register */ dspcntr = DISPPLANE_GAMMA_ENABLE; - if (pipe == 0) - dspcntr &= ~DISPPLANE_SEL_PIPE_MASK; - else - dspcntr |= DISPPLANE_SEL_PIPE_B; + if (!IS_VALLEYVIEW(dev)) { + if (pipe == 0) + dspcntr &= ~DISPPLANE_SEL_PIPE_MASK; + else + dspcntr |= DISPPLANE_SEL_PIPE_B; + } if (pipe == 0 && INTEL_INFO(dev)->gen < 4) { /* Enable pixel doubling when the dot clock is > 90% of the (display) From ed5de3995f9cdff997613f240e41033463703121 Mon Sep 17 00:00:00 2001 From: Jesse Barnes Date: Fri, 8 Mar 2013 10:45:57 -0800 Subject: [PATCH 65/79] drm/i915: add media well to VLV force wake routines v2 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We could split this out into a separate routine at some point as an optimization. v2: use FORCEWAKE_KERNEL (Ville) Note: Ville mentioned in his review that he declines to be responsible if this blows up due to the lack of "readback a register != FW_ACK, but from the same cacheline" magic we have in other forcewake implementations. Signed-off-by: Jesse Barnes Reviewed-by: Ville Syrjälä [danvet: Bikeshed overtly long lines according to checkpatch.pl. Nope, this time around I didn't screw up printk message since I've left those alone.] Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_reg.h | 2 ++ drivers/gpu/drm/i915/intel_pm.c | 14 +++++++++++--- 2 files changed, 13 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index 176cf5c58507..17cb78f5760a 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -4148,6 +4148,8 @@ #define FORCEWAKE 0xA18C #define FORCEWAKE_VLV 0x1300b0 #define FORCEWAKE_ACK_VLV 0x1300b4 +#define FORCEWAKE_MEDIA_VLV 0x1300b8 +#define FORCEWAKE_ACK_MEDIA_VLV 0x1300bc #define FORCEWAKE_ACK_HSW 0x130044 #define FORCEWAKE_ACK 0x130090 #define VLV_GTLC_WAKE_CTRL 0x130090 diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c index c30e89a45236..52d4f2d660db 100644 --- a/drivers/gpu/drm/i915/intel_pm.c +++ b/drivers/gpu/drm/i915/intel_pm.c @@ -4404,10 +4404,17 @@ static void vlv_force_wake_get(struct drm_i915_private *dev_priv) DRM_ERROR("Timed out waiting for forcewake old ack to clear.\n"); I915_WRITE_NOTRACE(FORCEWAKE_VLV, _MASKED_BIT_ENABLE(FORCEWAKE_KERNEL)); + I915_WRITE_NOTRACE(FORCEWAKE_MEDIA_VLV, + _MASKED_BIT_ENABLE(FORCEWAKE_KERNEL)); if (wait_for_atomic((I915_READ_NOTRACE(FORCEWAKE_ACK_VLV) & FORCEWAKE_KERNEL), FORCEWAKE_ACK_TIMEOUT_MS)) - DRM_ERROR("Timed out waiting for forcewake to ack request.\n"); + DRM_ERROR("Timed out waiting for GT to ack forcewake request.\n"); + + if (wait_for_atomic((I915_READ_NOTRACE(FORCEWAKE_ACK_MEDIA_VLV) & + FORCEWAKE_KERNEL), + FORCEWAKE_ACK_TIMEOUT_MS)) + DRM_ERROR("Timed out waiting for media to ack forcewake request.\n"); __gen6_gt_wait_for_thread_c0(dev_priv); } @@ -4415,8 +4422,9 @@ static void vlv_force_wake_get(struct drm_i915_private *dev_priv) static void vlv_force_wake_put(struct drm_i915_private *dev_priv) { I915_WRITE_NOTRACE(FORCEWAKE_VLV, _MASKED_BIT_DISABLE(FORCEWAKE_KERNEL)); - /* something from same cacheline, but !FORCEWAKE_VLV */ - POSTING_READ(FORCEWAKE_ACK_VLV); + I915_WRITE_NOTRACE(FORCEWAKE_MEDIA_VLV, + _MASKED_BIT_DISABLE(FORCEWAKE_KERNEL)); + /* The below doubles as a POSTING_READ */ gen6_gt_check_fifodbg(dev_priv); } From 7637bfdb54c11f3471bac7ebe4fdca46970e72af Mon Sep 17 00:00:00 2001 From: Jesse Barnes Date: Fri, 8 Mar 2013 10:46:01 -0800 Subject: [PATCH 66/79] drm/i915: use VLV DIP routines on VLV v2 This fixes up broken logic introduced in commit 90b107c8f7ea75ef55db4e0515dda86b245f8978 Author: Shobhit Kumar Date: Wed Mar 28 13:39:32 2012 -0700 drm/i915: Enable HDMI on ValleyView That one was probably a rebase fail along the way. v2: clean up init ordering (Daniel) Signed-off-by: Jesse Barnes [danvet: Pimp commit message a bit.] Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_hdmi.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_hdmi.c b/drivers/gpu/drm/i915/intel_hdmi.c index c882839cd51e..2474b1b6de61 100644 --- a/drivers/gpu/drm/i915/intel_hdmi.c +++ b/drivers/gpu/drm/i915/intel_hdmi.c @@ -1004,12 +1004,12 @@ void intel_hdmi_init_connector(struct intel_digital_port *intel_dig_port, BUG(); } - if (!HAS_PCH_SPLIT(dev)) { - intel_hdmi->write_infoframe = g4x_write_infoframe; - intel_hdmi->set_infoframes = g4x_set_infoframes; - } else if (IS_VALLEYVIEW(dev)) { + if (IS_VALLEYVIEW(dev)) { intel_hdmi->write_infoframe = vlv_write_infoframe; intel_hdmi->set_infoframes = vlv_set_infoframes; + } else if (!HAS_PCH_SPLIT(dev)) { + intel_hdmi->write_infoframe = g4x_write_infoframe; + intel_hdmi->set_infoframes = g4x_set_infoframes; } else if (HAS_DDI(dev)) { intel_hdmi->write_infoframe = hsw_write_infoframe; intel_hdmi->set_infoframes = hsw_set_infoframes; From d7fee5f6faea17b6e702eba90037ab8f716faf8e Mon Sep 17 00:00:00 2001 From: Jesse Barnes Date: Fri, 8 Mar 2013 10:45:50 -0800 Subject: [PATCH 67/79] drm/i915: add more VLV IDs Signed-off-by: Jesse Barnes Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_drv.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/gpu/drm/i915/i915_drv.c b/drivers/gpu/drm/i915/i915_drv.c index db3099845877..2e4b4a3a77d2 100644 --- a/drivers/gpu/drm/i915/i915_drv.c +++ b/drivers/gpu/drm/i915/i915_drv.c @@ -389,6 +389,9 @@ static const struct pci_device_id pciidlist[] = { /* aka */ INTEL_VGA_DEVICE(0x0D16, &intel_haswell_m_info), /* CRW GT2 mobile */ INTEL_VGA_DEVICE(0x0D26, &intel_haswell_m_info), /* CRW GT2 mobile */ INTEL_VGA_DEVICE(0x0f30, &intel_valleyview_m_info), + INTEL_VGA_DEVICE(0x0f31, &intel_valleyview_m_info), + INTEL_VGA_DEVICE(0x0f32, &intel_valleyview_m_info), + INTEL_VGA_DEVICE(0x0f33, &intel_valleyview_m_info), INTEL_VGA_DEVICE(0x0157, &intel_valleyview_m_info), INTEL_VGA_DEVICE(0x0155, &intel_valleyview_d_info), {0, 0, 0} From d3bc03030a3994181d420e9f3b858fe6edd71839 Mon Sep 17 00:00:00 2001 From: Jesse Barnes Date: Fri, 8 Mar 2013 10:45:51 -0800 Subject: [PATCH 68/79] drm/i915: fix WaDisablePSDDualDispatchEnable on VLV v2 Can prevent a hang when we get to tessellation. We need to set bit 15 as well for this workaround. v2: update changelog with accurate info Signed-off-by: Jesse Barnes Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_pm.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c index 52d4f2d660db..0bb94d963b0a 100644 --- a/drivers/gpu/drm/i915/intel_pm.c +++ b/drivers/gpu/drm/i915/intel_pm.c @@ -3899,8 +3899,10 @@ static void valleyview_init_clock_gating(struct drm_device *dev) CHICKEN3_DGMG_REQ_OUT_FIX_DISABLE | CHICKEN3_DGMG_DONE_FIX_DISABLE); + /* WaDisablePSDDualDispatchEnable */ I915_WRITE(GEN7_HALF_SLICE_CHICKEN1, - _MASKED_BIT_ENABLE(GEN7_PSD_SINGLE_PORT_DISPATCH_ENABLE)); + _MASKED_BIT_ENABLE(GEN7_MAX_PS_THREAD_DEP | + GEN7_PSD_SINGLE_PORT_DISPATCH_ENABLE)); /* Apply the WaDisableRHWOOptimizationForRenderHang workaround. */ I915_WRITE(GEN7_COMMON_SLICE_CHICKEN1, From 4e8c84a5b14bbb5b88c63941f1d939560f4abd0b Mon Sep 17 00:00:00 2001 From: Jesse Barnes Date: Fri, 8 Mar 2013 10:45:54 -0800 Subject: [PATCH 69/79] drm/i915: set conservative clock gating values on VLV v2 We'll re-enable select bits as needed after testing and power measurement. v2: split out wake handling bits (Jani) Signed-off-by: Jesse Barnes Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_pm.c | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c index 0bb94d963b0a..8a3d89ecae69 100644 --- a/drivers/gpu/drm/i915/intel_pm.c +++ b/drivers/gpu/drm/i915/intel_pm.c @@ -3987,7 +3987,16 @@ static void valleyview_init_clock_gating(struct drm_device *dev) * Disable clock gating on th GCFG unit to prevent a delay * in the reporting of vblank events. */ - I915_WRITE(VLV_GUNIT_CLOCK_GATE, GCFG_DIS); + I915_WRITE(VLV_GUNIT_CLOCK_GATE, 0xffffffff); + + /* Conservative clock gating settings for now */ + I915_WRITE(0x9400, 0xffffffff); + I915_WRITE(0x9404, 0xffffffff); + I915_WRITE(0x9408, 0xffffffff); + I915_WRITE(0x940c, 0xffffffff); + I915_WRITE(0x9410, 0xffffffff); + I915_WRITE(0x9414, 0xffffffff); + I915_WRITE(0x9418, 0xffffffff); } static void g4x_init_clock_gating(struct drm_device *dev) From 12569ad6eaee31033333882a74df71588a8584c2 Mon Sep 17 00:00:00 2001 From: Jesse Barnes Date: Fri, 8 Mar 2013 10:45:59 -0800 Subject: [PATCH 70/79] drm/i915: DSPFW and BLC regs are in the display offset range Signed-off-by: Jesse Barnes Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_reg.h | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index 17cb78f5760a..50dba38f5035 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -1923,7 +1923,7 @@ #define PFIT_AUTO_RATIOS (dev_priv->info->display_mmio_offset + 0x61238) /* Backlight control */ -#define BLC_PWM_CTL2 0x61250 /* 965+ only */ +#define BLC_PWM_CTL2 (dev_priv->info->display_mmio_offset + 0x61250) /* 965+ only */ #define BLM_PWM_ENABLE (1 << 31) #define BLM_COMBINATION_MODE (1 << 30) /* gen4 only */ #define BLM_PIPE_SELECT (1 << 29) @@ -1942,7 +1942,7 @@ #define BLM_PHASE_IN_COUNT_MASK (0xff << 8) #define BLM_PHASE_IN_INCR_SHIFT (0) #define BLM_PHASE_IN_INCR_MASK (0xff << 0) -#define BLC_PWM_CTL 0x61254 +#define BLC_PWM_CTL (dev_priv->info->display_mmio_offset + 0x61254) /* * This is the most significant 15 bits of the number of backlight cycles in a * complete cycle of the modulated backlight control. @@ -1964,7 +1964,7 @@ #define BACKLIGHT_DUTY_CYCLE_MASK_PNV (0xfffe) #define BLM_POLARITY_PNV (1 << 0) /* pnv only */ -#define BLC_HIST_CTL 0x61260 +#define BLC_HIST_CTL (dev_priv->info->display_mmio_offset + 0x61260) /* New registers for PCH-split platforms. Safe where new bits show up, the * register layout machtes with gen4 BLC_PWM_CTL[12]. */ @@ -2801,6 +2801,8 @@ #define DSPFW_HPLL_CURSOR_SHIFT 16 #define DSPFW_HPLL_CURSOR_MASK (0x3f<<16) #define DSPFW_HPLL_SR_MASK (0x1ff) +#define DSPFW4 (dev_priv->info->display_mmio_offset + 0x70070) +#define DSPFW7 (dev_priv->info->display_mmio_offset + 0x7007c) /* drain latency register values*/ #define DRAIN_LATENCY_PRECISION_32 32 From 34c61c6e0b4cb3b05895b28823eb9f1da925ad87 Mon Sep 17 00:00:00 2001 From: Jesse Barnes Date: Fri, 8 Mar 2013 10:46:03 -0800 Subject: [PATCH 71/79] drm/i915: VLV doesn't have HDMI on port C Port C is for eDP. Port B is shared between HDMI and DP. Signed-off-by: Jesse Barnes Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_display.c | 5 ----- 1 file changed, 5 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 6953f88bf04d..72dd3fd8e9c1 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -8405,11 +8405,6 @@ static void intel_setup_outputs(struct drm_device *dev) if (I915_READ(VLV_DISPLAY_BASE + DP_B) & DP_DETECTED) intel_dp_init(dev, VLV_DISPLAY_BASE + DP_B, PORT_B); } - - if (I915_READ(VLV_DISPLAY_BASE + GEN4_HDMIC) & SDVO_DETECTED) - intel_hdmi_init(dev, VLV_DISPLAY_BASE + GEN4_HDMIC, - PORT_C); - } else if (SUPPORTS_DIGITAL_OUTPUTS(dev)) { bool found = false; From 6ddc4fc70ad689bc33fab801e29d14426a514d41 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Tue, 19 Mar 2013 23:37:08 +0100 Subject: [PATCH 72/79] style nit: Align function parameter continuation properly. --- 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 c0ccbe7b61bc..414dee49dfbf 100644 --- a/drivers/gpu/drm/i915/i915_gem_gtt.c +++ b/drivers/gpu/drm/i915/i915_gem_gtt.c @@ -126,7 +126,7 @@ static void gen6_ppgtt_insert_entries(struct i915_hw_ppgtt *ppgtt, page_addr = sg_dma_address(sg_iter.sg) + (sg_iter.sg_pgoffset << PAGE_SHIFT); pt_vaddr[act_pte] = gen6_pte_encode(ppgtt->dev, page_addr, - cache_level); + cache_level); if (++act_pte == I915_PPGTT_PT_ENTRIES) { kunmap_atomic(pt_vaddr); act_pd++; From a15326a57c4d282803765b0a45c53ea4a8c2c94b Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Tue, 19 Mar 2013 23:48:39 +0100 Subject: [PATCH 73/79] drm/i915: fixup pd vs pt confusion in gen6 ppgtt code The index variable points at a page table, not a page directory or a pde. Ben Widawsky fix this up correctly in his ppgtt cleanup, but I've botched the job and copy&pasted the old confusion from the original gen6 ppgtt code in commit def886c3768d24c4e0aa56ff98b5a468c2b5c9bf Author: Daniel Vetter Date: Thu Jan 24 14:44:56 2013 -0800 drm/i915: vfuncs for ppgtt Reviewed-by: Ben Widawsky Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_gem_gtt.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_gem_gtt.c b/drivers/gpu/drm/i915/i915_gem_gtt.c index 414dee49dfbf..4cbae7bbb833 100644 --- a/drivers/gpu/drm/i915/i915_gem_gtt.c +++ b/drivers/gpu/drm/i915/i915_gem_gtt.c @@ -83,7 +83,7 @@ static void gen6_ppgtt_clear_range(struct i915_hw_ppgtt *ppgtt, { gtt_pte_t *pt_vaddr; gtt_pte_t scratch_pte; - unsigned act_pd = first_entry / I915_PPGTT_PT_ENTRIES; + unsigned act_pt = first_entry / I915_PPGTT_PT_ENTRIES; unsigned first_pte = first_entry % I915_PPGTT_PT_ENTRIES; unsigned last_pte, i; @@ -96,7 +96,7 @@ static void gen6_ppgtt_clear_range(struct i915_hw_ppgtt *ppgtt, if (last_pte > I915_PPGTT_PT_ENTRIES) last_pte = I915_PPGTT_PT_ENTRIES; - pt_vaddr = kmap_atomic(ppgtt->pt_pages[act_pd]); + pt_vaddr = kmap_atomic(ppgtt->pt_pages[act_pt]); for (i = first_pte; i < last_pte; i++) pt_vaddr[i] = scratch_pte; @@ -105,7 +105,7 @@ static void gen6_ppgtt_clear_range(struct i915_hw_ppgtt *ppgtt, num_entries -= last_pte - first_pte; first_pte = 0; - act_pd++; + act_pt++; } } @@ -115,11 +115,11 @@ static void gen6_ppgtt_insert_entries(struct i915_hw_ppgtt *ppgtt, enum i915_cache_level cache_level) { gtt_pte_t *pt_vaddr; - unsigned act_pd = first_entry / I915_PPGTT_PT_ENTRIES; + unsigned act_pt = first_entry / I915_PPGTT_PT_ENTRIES; unsigned act_pte = first_entry % I915_PPGTT_PT_ENTRIES; struct sg_page_iter sg_iter; - pt_vaddr = kmap_atomic(ppgtt->pt_pages[act_pd]); + pt_vaddr = kmap_atomic(ppgtt->pt_pages[act_pt]); for_each_sg_page(pages->sgl, &sg_iter, pages->nents, 0) { dma_addr_t page_addr; @@ -129,8 +129,8 @@ static void gen6_ppgtt_insert_entries(struct i915_hw_ppgtt *ppgtt, cache_level); if (++act_pte == I915_PPGTT_PT_ENTRIES) { kunmap_atomic(pt_vaddr); - act_pd++; - pt_vaddr = kmap_atomic(ppgtt->pt_pages[act_pd]); + act_pt++; + pt_vaddr = kmap_atomic(ppgtt->pt_pages[act_pt]); act_pte = 0; } From 7eb552aeae058a88eece91b902dd51fde45b1f41 Mon Sep 17 00:00:00 2001 From: Ben Widawsky Date: Wed, 13 Mar 2013 14:05:41 -0700 Subject: [PATCH 74/79] drm/i915: Move num_pipes to intel info Requested by Daniel. v2: Fix incorrect num_pipe settings. (Chris) Cc: Daniel Vetter Signed-off-by: Ben Widawsky Reviewed-by: Jesse Barnes Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_dma.c | 9 +----- drivers/gpu/drm/i915/i915_drv.c | 48 ++++++++++++++-------------- drivers/gpu/drm/i915/i915_drv.h | 4 +-- drivers/gpu/drm/i915/i915_irq.c | 3 +- drivers/gpu/drm/i915/intel_display.c | 19 +++++------ drivers/gpu/drm/i915/intel_fb.c | 2 +- drivers/gpu/drm/i915/intel_panel.c | 2 +- 7 files changed, 40 insertions(+), 47 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_dma.c b/drivers/gpu/drm/i915/i915_dma.c index e16099b6f942..ebcfe2e9497f 100644 --- a/drivers/gpu/drm/i915/i915_dma.c +++ b/drivers/gpu/drm/i915/i915_dma.c @@ -1630,14 +1630,7 @@ int i915_driver_load(struct drm_device *dev, unsigned long flags) mutex_init(&dev_priv->rps.hw_lock); mutex_init(&dev_priv->modeset_restore_lock); - if (IS_IVYBRIDGE(dev) || IS_HASWELL(dev)) - dev_priv->num_pipe = 3; - else if (IS_MOBILE(dev) || !IS_GEN2(dev)) - dev_priv->num_pipe = 2; - else - dev_priv->num_pipe = 1; - - ret = drm_vblank_init(dev, dev_priv->num_pipe); + ret = drm_vblank_init(dev, INTEL_INFO(dev)->num_pipes); if (ret) goto out_gem_unload; diff --git a/drivers/gpu/drm/i915/i915_drv.c b/drivers/gpu/drm/i915/i915_drv.c index 2e4b4a3a77d2..788ae5bd1bfe 100644 --- a/drivers/gpu/drm/i915/i915_drv.c +++ b/drivers/gpu/drm/i915/i915_drv.c @@ -136,74 +136,74 @@ extern int intel_agp_enabled; .driver_data = (unsigned long) info } static const struct intel_device_info intel_i830_info = { - .gen = 2, .is_mobile = 1, .cursor_needs_physical = 1, + .gen = 2, .is_mobile = 1, .cursor_needs_physical = 1, .num_pipes = 2, .has_overlay = 1, .overlay_needs_physical = 1, }; static const struct intel_device_info intel_845g_info = { - .gen = 2, + .gen = 2, .num_pipes = 1, .has_overlay = 1, .overlay_needs_physical = 1, }; static const struct intel_device_info intel_i85x_info = { - .gen = 2, .is_i85x = 1, .is_mobile = 1, + .gen = 2, .is_i85x = 1, .is_mobile = 1, .num_pipes = 2, .cursor_needs_physical = 1, .has_overlay = 1, .overlay_needs_physical = 1, }; static const struct intel_device_info intel_i865g_info = { - .gen = 2, + .gen = 2, .num_pipes = 1, .has_overlay = 1, .overlay_needs_physical = 1, }; static const struct intel_device_info intel_i915g_info = { - .gen = 3, .is_i915g = 1, .cursor_needs_physical = 1, + .gen = 3, .is_i915g = 1, .cursor_needs_physical = 1, .num_pipes = 2, .has_overlay = 1, .overlay_needs_physical = 1, }; static const struct intel_device_info intel_i915gm_info = { - .gen = 3, .is_mobile = 1, + .gen = 3, .is_mobile = 1, .num_pipes = 2, .cursor_needs_physical = 1, .has_overlay = 1, .overlay_needs_physical = 1, .supports_tv = 1, }; static const struct intel_device_info intel_i945g_info = { - .gen = 3, .has_hotplug = 1, .cursor_needs_physical = 1, + .gen = 3, .has_hotplug = 1, .cursor_needs_physical = 1, .num_pipes = 2, .has_overlay = 1, .overlay_needs_physical = 1, }; static const struct intel_device_info intel_i945gm_info = { - .gen = 3, .is_i945gm = 1, .is_mobile = 1, + .gen = 3, .is_i945gm = 1, .is_mobile = 1, .num_pipes = 2, .has_hotplug = 1, .cursor_needs_physical = 1, .has_overlay = 1, .overlay_needs_physical = 1, .supports_tv = 1, }; static const struct intel_device_info intel_i965g_info = { - .gen = 4, .is_broadwater = 1, + .gen = 4, .is_broadwater = 1, .num_pipes = 2, .has_hotplug = 1, .has_overlay = 1, }; static const struct intel_device_info intel_i965gm_info = { - .gen = 4, .is_crestline = 1, + .gen = 4, .is_crestline = 1, .num_pipes = 2, .is_mobile = 1, .has_fbc = 1, .has_hotplug = 1, .has_overlay = 1, .supports_tv = 1, }; static const struct intel_device_info intel_g33_info = { - .gen = 3, .is_g33 = 1, + .gen = 3, .is_g33 = 1, .num_pipes = 2, .need_gfx_hws = 1, .has_hotplug = 1, .has_overlay = 1, }; static const struct intel_device_info intel_g45_info = { - .gen = 4, .is_g4x = 1, .need_gfx_hws = 1, + .gen = 4, .is_g4x = 1, .need_gfx_hws = 1, .num_pipes = 2, .has_pipe_cxsr = 1, .has_hotplug = 1, .has_bsd_ring = 1, }; static const struct intel_device_info intel_gm45_info = { - .gen = 4, .is_g4x = 1, + .gen = 4, .is_g4x = 1, .num_pipes = 2, .is_mobile = 1, .need_gfx_hws = 1, .has_fbc = 1, .has_pipe_cxsr = 1, .has_hotplug = 1, .supports_tv = 1, @@ -211,26 +211,26 @@ static const struct intel_device_info intel_gm45_info = { }; static const struct intel_device_info intel_pineview_info = { - .gen = 3, .is_g33 = 1, .is_pineview = 1, .is_mobile = 1, + .gen = 3, .is_g33 = 1, .is_pineview = 1, .is_mobile = 1, .num_pipes = 2, .need_gfx_hws = 1, .has_hotplug = 1, .has_overlay = 1, }; static const struct intel_device_info intel_ironlake_d_info = { - .gen = 5, + .gen = 5, .num_pipes = 2, .need_gfx_hws = 1, .has_hotplug = 1, .has_bsd_ring = 1, }; static const struct intel_device_info intel_ironlake_m_info = { - .gen = 5, .is_mobile = 1, + .gen = 5, .is_mobile = 1, .num_pipes = 2, .need_gfx_hws = 1, .has_hotplug = 1, .has_fbc = 1, .has_bsd_ring = 1, }; static const struct intel_device_info intel_sandybridge_d_info = { - .gen = 6, + .gen = 6, .num_pipes = 2, .need_gfx_hws = 1, .has_hotplug = 1, .has_bsd_ring = 1, .has_blt_ring = 1, @@ -239,7 +239,7 @@ static const struct intel_device_info intel_sandybridge_d_info = { }; static const struct intel_device_info intel_sandybridge_m_info = { - .gen = 6, .is_mobile = 1, + .gen = 6, .is_mobile = 1, .num_pipes = 2, .need_gfx_hws = 1, .has_hotplug = 1, .has_fbc = 1, .has_bsd_ring = 1, @@ -249,7 +249,7 @@ static const struct intel_device_info intel_sandybridge_m_info = { }; static const struct intel_device_info intel_ivybridge_d_info = { - .is_ivybridge = 1, .gen = 7, + .is_ivybridge = 1, .gen = 7, .num_pipes = 3, .need_gfx_hws = 1, .has_hotplug = 1, .has_bsd_ring = 1, .has_blt_ring = 1, @@ -258,7 +258,7 @@ static const struct intel_device_info intel_ivybridge_d_info = { }; static const struct intel_device_info intel_ivybridge_m_info = { - .is_ivybridge = 1, .gen = 7, .is_mobile = 1, + .is_ivybridge = 1, .gen = 7, .is_mobile = 1, .num_pipes = 3, .need_gfx_hws = 1, .has_hotplug = 1, .has_fbc = 0, /* FBC is not enabled on Ivybridge mobile yet */ .has_bsd_ring = 1, @@ -268,7 +268,7 @@ static const struct intel_device_info intel_ivybridge_m_info = { }; static const struct intel_device_info intel_valleyview_m_info = { - .gen = 7, .is_mobile = 1, + .gen = 7, .is_mobile = 1, .num_pipes = 2, .need_gfx_hws = 1, .has_hotplug = 1, .has_fbc = 0, .has_bsd_ring = 1, @@ -279,7 +279,7 @@ static const struct intel_device_info intel_valleyview_m_info = { }; static const struct intel_device_info intel_valleyview_d_info = { - .gen = 7, + .gen = 7, .num_pipes = 2, .need_gfx_hws = 1, .has_hotplug = 1, .has_fbc = 0, .has_bsd_ring = 1, @@ -290,7 +290,7 @@ static const struct intel_device_info intel_valleyview_d_info = { }; static const struct intel_device_info intel_haswell_d_info = { - .is_haswell = 1, .gen = 7, + .is_haswell = 1, .gen = 7, .num_pipes = 3, .need_gfx_hws = 1, .has_hotplug = 1, .has_bsd_ring = 1, .has_blt_ring = 1, @@ -299,7 +299,7 @@ static const struct intel_device_info intel_haswell_d_info = { }; static const struct intel_device_info intel_haswell_m_info = { - .is_haswell = 1, .gen = 7, .is_mobile = 1, + .is_haswell = 1, .gen = 7, .is_mobile = 1, .num_pipes = 3, .need_gfx_hws = 1, .has_hotplug = 1, .has_bsd_ring = 1, .has_blt_ring = 1, diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 1246a31c0243..1657d8733648 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -93,7 +93,7 @@ enum port { I915_GEM_DOMAIN_INSTRUCTION | \ I915_GEM_DOMAIN_VERTEX) -#define for_each_pipe(p) for ((p) = 0; (p) < dev_priv->num_pipe; (p)++) +#define for_each_pipe(p) for ((p) = 0; (p) < INTEL_INFO(dev)->num_pipes; (p)++) #define for_each_encoder_on_crtc(dev, __crtc, intel_encoder) \ list_for_each_entry((intel_encoder), &(dev)->mode_config.encoder_list, base.head) \ @@ -341,6 +341,7 @@ struct drm_i915_gt_funcs { struct intel_device_info { u32 display_mmio_offset; + u8 num_pipes:3; u8 gen; u8 is_mobile:1; u8 is_i85x:1; @@ -912,7 +913,6 @@ typedef struct drm_i915_private { struct work_struct hotplug_work; bool enable_hotplug_processing; - int num_pipe; int num_pch_pll; unsigned long cfb_size; diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c index 62285ff03083..5fc178e1e515 100644 --- a/drivers/gpu/drm/i915/i915_irq.c +++ b/drivers/gpu/drm/i915/i915_irq.c @@ -254,10 +254,9 @@ static int i915_get_vblank_timestamp(struct drm_device *dev, int pipe, struct timeval *vblank_time, unsigned flags) { - struct drm_i915_private *dev_priv = dev->dev_private; struct drm_crtc *crtc; - if (pipe < 0 || pipe >= dev_priv->num_pipe) { + if (pipe < 0 || pipe >= INTEL_INFO(dev)->num_pipes) { DRM_ERROR("Invalid crtc %d\n", pipe); return -EINVAL; } diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 72dd3fd8e9c1..b3b22d7d2cd0 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -2346,10 +2346,10 @@ intel_pipe_set_base(struct drm_crtc *crtc, int x, int y, return 0; } - if(intel_crtc->plane > dev_priv->num_pipe) { + if (intel_crtc->plane > INTEL_INFO(dev)->num_pipes) { DRM_ERROR("no plane for crtc: plane %d, num_pipes %d\n", intel_crtc->plane, - dev_priv->num_pipe); + INTEL_INFO(dev)->num_pipes); return -EINVAL; } @@ -5390,7 +5390,7 @@ static bool ironlake_check_fdi_lanes(struct intel_crtc *intel_crtc) return false; } - if (dev_priv->num_pipe == 2) + if (INTEL_INFO(dev)->num_pipes == 2) return true; switch (intel_crtc->pipe) { @@ -8887,9 +8887,10 @@ void intel_modeset_init(struct drm_device *dev) 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" : ""); + INTEL_INFO(dev)->num_pipes, + INTEL_INFO(dev)->num_pipes > 1 ? "s" : ""); - for (i = 0; i < dev_priv->num_pipe; i++) { + for (i = 0; i < INTEL_INFO(dev)->num_pipes; i++) { intel_crtc_init(dev, i); ret = intel_plane_init(dev, i); if (ret) @@ -8946,10 +8947,11 @@ static void intel_enable_pipe_a(struct drm_device *dev) static bool intel_check_plane_mapping(struct intel_crtc *crtc) { - struct drm_i915_private *dev_priv = crtc->base.dev->dev_private; + struct drm_device *dev = crtc->base.dev; + struct drm_i915_private *dev_priv = dev->dev_private; u32 reg, val; - if (dev_priv->num_pipe == 1) + if (INTEL_INFO(dev)->num_pipes == 1) return true; reg = DSPCNTR(!crtc->plane); @@ -9391,10 +9393,9 @@ intel_display_print_error_state(struct seq_file *m, struct drm_device *dev, struct intel_display_error_state *error) { - drm_i915_private_t *dev_priv = dev->dev_private; int i; - seq_printf(m, "Num Pipes: %d\n", dev_priv->num_pipe); + seq_printf(m, "Num Pipes: %d\n", INTEL_INFO(dev)->num_pipes); for_each_pipe(i) { seq_printf(m, "Pipe [%d]:\n", i); seq_printf(m, " CONF: %08x\n", error->pipe[i].conf); diff --git a/drivers/gpu/drm/i915/intel_fb.c b/drivers/gpu/drm/i915/intel_fb.c index 510a96047ae4..f203418b6f05 100644 --- a/drivers/gpu/drm/i915/intel_fb.c +++ b/drivers/gpu/drm/i915/intel_fb.c @@ -225,7 +225,7 @@ int intel_fbdev_init(struct drm_device *dev) ifbdev->helper.funcs = &intel_fb_helper_funcs; ret = drm_fb_helper_init(dev, &ifbdev->helper, - dev_priv->num_pipe, + INTEL_INFO(dev)->num_pipes, INTELFB_CONN_LIMIT); if (ret) { kfree(ifbdev); diff --git a/drivers/gpu/drm/i915/intel_panel.c b/drivers/gpu/drm/i915/intel_panel.c index a3730e0289e5..f1530f4ad7fe 100644 --- a/drivers/gpu/drm/i915/intel_panel.c +++ b/drivers/gpu/drm/i915/intel_panel.c @@ -338,7 +338,7 @@ void intel_panel_enable_backlight(struct drm_device *dev, if (tmp & BLM_PWM_ENABLE) goto set_level; - if (dev_priv->num_pipe == 3) + if (INTEL_INFO(dev)->num_pipes == 3) tmp &= ~BLM_PIPE_SELECT_IVB; else tmp &= ~BLM_PIPE_SELECT; From 219f4fdbed5570f1d2e8da0af1c298dd3622060e Mon Sep 17 00:00:00 2001 From: Ben Widawsky Date: Fri, 15 Mar 2013 11:17:54 -0700 Subject: [PATCH 75/79] drm/i915: Introduce GEN7_FEATURES for device info Recommended by Chris. v2: Make it GEN7_FEATURES, and use it for vlv and hsw also (Ben) Cc: Chris Wilson Signed-off-by: Ben Widawsky Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_drv.c | 60 +++++++++++++-------------------- 1 file changed, 23 insertions(+), 37 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_drv.c b/drivers/gpu/drm/i915/i915_drv.c index 788ae5bd1bfe..6c4b13c0ee77 100644 --- a/drivers/gpu/drm/i915/i915_drv.c +++ b/drivers/gpu/drm/i915/i915_drv.c @@ -248,63 +248,49 @@ static const struct intel_device_info intel_sandybridge_m_info = { .has_force_wake = 1, }; +#define GEN7_FEATURES \ + .gen = 7, .num_pipes = 3, \ + .need_gfx_hws = 1, .has_hotplug = 1, \ + .has_bsd_ring = 1, \ + .has_blt_ring = 1, \ + .has_llc = 1, \ + .has_force_wake = 1 + static const struct intel_device_info intel_ivybridge_d_info = { - .is_ivybridge = 1, .gen = 7, .num_pipes = 3, - .need_gfx_hws = 1, .has_hotplug = 1, - .has_bsd_ring = 1, - .has_blt_ring = 1, - .has_llc = 1, - .has_force_wake = 1, + GEN7_FEATURES, + .is_ivybridge = 1, }; static const struct intel_device_info intel_ivybridge_m_info = { - .is_ivybridge = 1, .gen = 7, .is_mobile = 1, .num_pipes = 3, - .need_gfx_hws = 1, .has_hotplug = 1, - .has_fbc = 0, /* FBC is not enabled on Ivybridge mobile yet */ - .has_bsd_ring = 1, - .has_blt_ring = 1, - .has_llc = 1, - .has_force_wake = 1, + GEN7_FEATURES, + .is_ivybridge = 1, + .is_mobile = 1, }; static const struct intel_device_info intel_valleyview_m_info = { - .gen = 7, .is_mobile = 1, .num_pipes = 2, - .need_gfx_hws = 1, .has_hotplug = 1, - .has_fbc = 0, - .has_bsd_ring = 1, - .has_blt_ring = 1, + GEN7_FEATURES, + .is_mobile = 1, + .num_pipes = 2, .is_valleyview = 1, .display_mmio_offset = VLV_DISPLAY_BASE, - .has_force_wake = 1, }; static const struct intel_device_info intel_valleyview_d_info = { - .gen = 7, .num_pipes = 2, - .need_gfx_hws = 1, .has_hotplug = 1, - .has_fbc = 0, - .has_bsd_ring = 1, - .has_blt_ring = 1, + GEN7_FEATURES, + .num_pipes = 2, .is_valleyview = 1, .display_mmio_offset = VLV_DISPLAY_BASE, - .has_force_wake = 1, }; static const struct intel_device_info intel_haswell_d_info = { - .is_haswell = 1, .gen = 7, .num_pipes = 3, - .need_gfx_hws = 1, .has_hotplug = 1, - .has_bsd_ring = 1, - .has_blt_ring = 1, - .has_llc = 1, - .has_force_wake = 1, + GEN7_FEATURES, + .is_haswell = 1, }; static const struct intel_device_info intel_haswell_m_info = { - .is_haswell = 1, .gen = 7, .is_mobile = 1, .num_pipes = 3, - .need_gfx_hws = 1, .has_hotplug = 1, - .has_bsd_ring = 1, - .has_blt_ring = 1, - .has_llc = 1, - .has_force_wake = 1, + GEN7_FEATURES, + .is_haswell = 1, + .is_mobile = 1, }; static const struct pci_device_id pciidlist[] = { /* aka */ From a2b3fc0133083d2ab1edac9c3485eb80d1378dbb Mon Sep 17 00:00:00 2001 From: Ben Widawsky Date: Tue, 19 Mar 2013 20:19:56 -0700 Subject: [PATCH 76/79] drm/i915: Correct sandybrige overclocking Change the gen6+ max delay if the pcode read was successful (not the inverse). The previous code was all sorts of wrong and has existed since I broke it: commit 42c0526c930523425ff6edc95b7235ce7ab9308d Author: Ben Widawsky Date: Wed Sep 26 10:34:00 2012 -0700 drm/i915: Extract PCU communication I added some parentheses for clarity, and I also corrected the debug message message to use the mask (wrong before I came along) and added a print to show the value we're changing from. Looking over the code, I'm not actually sure what we're trying to do. I introduced the bug simply by extracting the function not implementing anything new. We already set max_delay based on the capabilities register (which is what we use elsewhere to determine min and max). This would potentially increase it, I suppose? Jesse, I can't find the document which explains the definitions of the pcode commands, maybe you have it around. Based on Jesse's response, this could potentially be for -fixes, or stable, or maybe lead to us dropping it entirely. As the current code is is, things won't completely break because of the aforementioned capabilities register, and in my experimentation, enabling this has no effect, it goes from 1100->1100. I found this while reviewing Jesse's VLV patches. Cc: Jesse Barnes Signed-off-by: Ben Widawsky Reviewed-by: Jesse Barnes [danvet: Bikeshed-away the redudant parens spotted by Chris Wilson.] Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_pm.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c index 8a3d89ecae69..234f74183422 100644 --- a/drivers/gpu/drm/i915/intel_pm.c +++ b/drivers/gpu/drm/i915/intel_pm.c @@ -2631,9 +2631,11 @@ static void gen6_enable_rps(struct drm_device *dev) if (!ret) { pcu_mbox = 0; ret = sandybridge_pcode_read(dev_priv, GEN6_READ_OC_PARAMS, &pcu_mbox); - if (ret && pcu_mbox & (1<<31)) { /* OC supported */ + if (!ret && (pcu_mbox & (1<<31))) { /* OC supported */ + DRM_DEBUG_DRIVER("overclocking supported, adjusting frequency max from %dMHz to %dMHz\n", + (dev_priv->rps.max_delay & 0xff) * 50, + (pcu_mbox & 0xff) * 50); dev_priv->rps.max_delay = pcu_mbox & 0xff; - DRM_DEBUG_DRIVER("overclocking supported, adjusting frequency max to %dMHz\n", pcu_mbox * 50); } } else { DRM_DEBUG_DRIVER("Failed to set the min frequency\n"); From 65533633f7f573ebe898fabc6129705be9d855d0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Wed, 20 Mar 2013 17:05:09 +0200 Subject: [PATCH 77/79] drm/i915: Kill a strange comment about DPMS functions MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This comment looks like some historical leftover. Get rid of it. Signed-off-by: Ville Syrjälä Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_display.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index b3b22d7d2cd0..ec26a852df39 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -8600,7 +8600,6 @@ static void intel_init_display(struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; - /* We always want a DPMS function */ if (HAS_DDI(dev)) { dev_priv->display.crtc_mode_set = haswell_crtc_mode_set; dev_priv->display.crtc_enable = haswell_crtc_enable; From 96b219fac3b935b67929020a3b56800bd94ed640 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Wed, 20 Mar 2013 18:10:07 +0200 Subject: [PATCH 78/79] drm/i915: Set the VIC in AVI infoframe for SDVO MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We do this for HDMI already, so I don't know why we wouldn't do it for SDVO as well. This is completely untested due to lack of hardware. Signed-off-by: Ville Syrjälä Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_sdvo.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/gpu/drm/i915/intel_sdvo.c b/drivers/gpu/drm/i915/intel_sdvo.c index 53005260cd1d..678c47cac72b 100644 --- a/drivers/gpu/drm/i915/intel_sdvo.c +++ b/drivers/gpu/drm/i915/intel_sdvo.c @@ -965,6 +965,8 @@ static bool intel_sdvo_set_avi_infoframe(struct intel_sdvo *intel_sdvo, avi_if.body.avi.ITC_EC_Q_SC |= DIP_AVI_RGB_QUANT_RANGE_FULL; } + avi_if.body.avi.VIC = drm_match_cea_mode(adjusted_mode); + intel_dip_infoframe_csum(&avi_if); /* sdvo spec says that the ecc is handled by the hw, and it looks like From e3dff585508636c8d2915cc1595e04f16ccd66ba Mon Sep 17 00:00:00 2001 From: Ben Widawsky Date: Wed, 20 Mar 2013 14:49:14 -0700 Subject: [PATCH 79/79] drm/i915: Implement WaSwitchSolVfFArbitrationPriority Bspec mentions this for HSW+. I can't quite tell what the effects are, and I don't easily have a way to test this. Signed-off-by: Ben Widawsky Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_reg.h | 1 + drivers/gpu/drm/i915/intel_pm.c | 3 +++ 2 files changed, 4 insertions(+) diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index 50dba38f5035..bceca1159137 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -121,6 +121,7 @@ #define GAM_ECOCHK 0x4090 #define ECOCHK_SNB_BIT (1<<10) +#define HSW_ECOCHK_ARB_PRIO_SOL (1<<6) #define ECOCHK_PPGTT_CACHE64B (0x3<<3) #define ECOCHK_PPGTT_CACHE4B (0x0<<3) diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c index 234f74183422..ce3db2c1f1d9 100644 --- a/drivers/gpu/drm/i915/intel_pm.c +++ b/drivers/gpu/drm/i915/intel_pm.c @@ -3770,6 +3770,9 @@ static void haswell_init_clock_gating(struct drm_device *dev) I915_WRITE(GEN6_MBCTL, I915_READ(GEN6_MBCTL) | GEN6_MBCTL_ENABLE_BOOT_FETCH); + /* WaSwitchSolVfFArbitrationPriority */ + I915_WRITE(GAM_ECOCHK, I915_READ(GAM_ECOCHK) | HSW_ECOCHK_ARB_PRIO_SOL); + /* XXX: This is a workaround for early silicon revisions and should be * removed later. */