From ba86bf8bfc1add5f515db8cf1d6042bb9396a299 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Tue, 20 Oct 2009 16:29:16 +0000 Subject: drm/i915: Avoid potential sleep whilst holding spinlock Miles Lane reported the following error: 2 locks held by cat/4179: #0: (&p->lock){+.+.+.}, at: [] seq_read+0x25/0x315 #1: (&dev_priv->mm.active_list_lock){+.+...}, at: [] i915_batchbuffer_info+0x2b/0x124 Pid: 4179, comm: cat Not tainted 2.6.32-rc5-git1 #2 Call Trace: [] ? __debug_show_held_locks+0x1e/0x20 [] __might_sleep+0xf0/0xf7 [] kmap+0x17/0x58 [] i915_batchbuffer_info+0xad/0x124 [] seq_read+0x160/0x315 [] ? rw_verify_area+0x98/0xbb [] ? seq_read+0x0/0x315 [] vfs_read+0x75/0xa9 [] sys_read+0x3b/0x5d [] sysenter_do_call+0x12/0x36 The fix is relatively simple, use the atomic variants of kmap() that avoid the potential sleep. Signed-off-by: Chris Wilson Cc: Miles Lane Signed-off-by: Eric Anholt --- drivers/gpu/drm/i915/i915_debugfs.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/gpu/drm/i915') diff --git a/drivers/gpu/drm/i915/i915_debugfs.c b/drivers/gpu/drm/i915/i915_debugfs.c index f8ce9a3a420..26bf0552b3c 100644 --- a/drivers/gpu/drm/i915/i915_debugfs.c +++ b/drivers/gpu/drm/i915/i915_debugfs.c @@ -267,10 +267,10 @@ static void i915_dump_pages(struct seq_file *m, struct page **pages, int page_co uint32_t *mem; for (page = 0; page < page_count; page++) { - mem = kmap(pages[page]); + mem = kmap_atomic(pages[page], KM_USER0); for (i = 0; i < PAGE_SIZE; i += 4) seq_printf(m, "%08x : %08x\n", i, mem[i / 4]); - kunmap(pages[page]); + kunmap_atomic(pages[page], KM_USER0); } } -- cgit v1.2.3-18-g5258 From 4bfe6b6876a036d26a960320f1ab0bbd752c19bf Mon Sep 17 00:00:00 2001 From: Zhenyu Wang Date: Mon, 2 Nov 2009 07:52:29 +0000 Subject: drm/i915: Fix and cleanup DPLL calculation for Ironlake When the ideal error range can't be reached, this will safely use a most closed one. Clean up some dumb codes in DPLL function too. This fixes DPLL clock issue against one monitor at 1680x1050@60hz. Signed-off-by: Zhenyu Wang Signed-off-by: Eric Anholt --- drivers/gpu/drm/i915/intel_display.c | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) (limited to 'drivers/gpu/drm/i915') diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 3ba6546b7c7..099f420de57 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -863,10 +863,8 @@ intel_igdng_find_best_PLL(const intel_limit_t *limit, struct drm_crtc *crtc, struct drm_device *dev = crtc->dev; struct drm_i915_private *dev_priv = dev->dev_private; intel_clock_t clock; - int max_n; - bool found; int err_most = 47; - found = false; + int err_min = 10000; /* eDP has only 2 clock choice, no n/m/p setting */ if (HAS_eDP) @@ -890,10 +888,9 @@ intel_igdng_find_best_PLL(const intel_limit_t *limit, struct drm_crtc *crtc, } memset(best_clock, 0, sizeof(*best_clock)); - max_n = limit->n.max; for (clock.p1 = limit->p1.max; clock.p1 >= limit->p1.min; clock.p1--) { /* based on hardware requriment prefer smaller n to precision */ - for (clock.n = limit->n.min; clock.n <= max_n; clock.n++) { + for (clock.n = limit->n.min; clock.n <= limit->n.max; clock.n++) { /* based on hardware requirment prefere larger m1,m2 */ for (clock.m1 = limit->m1.max; clock.m1 >= limit->m1.min; clock.m1--) { @@ -907,18 +904,18 @@ intel_igdng_find_best_PLL(const intel_limit_t *limit, struct drm_crtc *crtc, this_err = abs((10000 - (target*10000/clock.dot))); if (this_err < err_most) { *best_clock = clock; - err_most = this_err; - max_n = clock.n; - found = true; /* found on first matching */ goto out; + } else if (this_err < err_min) { + *best_clock = clock; + err_min = this_err; } } } } } out: - return found; + return true; } /* DisplayPort has only two frequencies, 162MHz and 270MHz */ -- cgit v1.2.3-18-g5258 From d8a2d0e00c0d5a0d55e14b884bff034205015e51 Mon Sep 17 00:00:00 2001 From: Zhenyu Wang Date: Mon, 2 Nov 2009 07:52:30 +0000 Subject: drm/i915: HDMI hardware workaround for Ironlake This brings some hardware workaround for HDMI port on PCH (Ibex Peak), which fixes unstable issues like during rotation. Signed-off-by: Zhenyu Wang Signed-off-by: Eric Anholt --- drivers/gpu/drm/i915/intel_hdmi.c | 26 ++++++++++++++++++++++---- 1 file changed, 22 insertions(+), 4 deletions(-) (limited to 'drivers/gpu/drm/i915') diff --git a/drivers/gpu/drm/i915/intel_hdmi.c b/drivers/gpu/drm/i915/intel_hdmi.c index 663ab6de0b5..c33451aec1b 100644 --- a/drivers/gpu/drm/i915/intel_hdmi.c +++ b/drivers/gpu/drm/i915/intel_hdmi.c @@ -77,14 +77,32 @@ static void intel_hdmi_dpms(struct drm_encoder *encoder, int mode) struct intel_hdmi_priv *hdmi_priv = intel_output->dev_priv; u32 temp; - if (mode != DRM_MODE_DPMS_ON) { - temp = I915_READ(hdmi_priv->sdvox_reg); + temp = I915_READ(hdmi_priv->sdvox_reg); + + /* HW workaround, need to toggle enable bit off and on for 12bpc, but + * we do this anyway which shows more stable in testing. + */ + if (IS_IGDNG(dev)) { I915_WRITE(hdmi_priv->sdvox_reg, temp & ~SDVO_ENABLE); + POSTING_READ(hdmi_priv->sdvox_reg); + } + + if (mode != DRM_MODE_DPMS_ON) { + temp &= ~SDVO_ENABLE; } else { - temp = I915_READ(hdmi_priv->sdvox_reg); - I915_WRITE(hdmi_priv->sdvox_reg, temp | SDVO_ENABLE); + temp |= SDVO_ENABLE; } + + I915_WRITE(hdmi_priv->sdvox_reg, temp); POSTING_READ(hdmi_priv->sdvox_reg); + + /* HW workaround, need to write this twice for issue that may result + * in first write getting masked. + */ + if (IS_IGDNG(dev)) { + I915_WRITE(hdmi_priv->sdvox_reg, temp); + POSTING_READ(hdmi_priv->sdvox_reg); + } } static void intel_hdmi_save(struct drm_connector *connector) -- cgit v1.2.3-18-g5258 From 2d109a845dd3074885db726892c629ab73dd0ed8 Mon Sep 17 00:00:00 2001 From: "Zou, Nanhai" Date: Fri, 6 Nov 2009 02:13:01 +0000 Subject: drm/i915: Fix IRQ stall issue on Ironlake The master irq control in DE must be disabled before irq handling, and enable after the process. This fixes the irq stall issue on Ironlake. Cc: Stable Team Signed-off-by: Zou, Nanhai Signed-off-by: Zhenyu Wang Signed-off-by: Eric Anholt --- drivers/gpu/drm/i915/i915_irq.c | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) (limited to 'drivers/gpu/drm/i915') diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c index c3ceffa46ea..aa7fd82aa6e 100644 --- a/drivers/gpu/drm/i915/i915_irq.c +++ b/drivers/gpu/drm/i915/i915_irq.c @@ -254,10 +254,15 @@ irqreturn_t igdng_irq_handler(struct drm_device *dev) { drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; int ret = IRQ_NONE; - u32 de_iir, gt_iir; + u32 de_iir, gt_iir, de_ier; u32 new_de_iir, new_gt_iir; struct drm_i915_master_private *master_priv; + /* disable master interrupt before clearing iir */ + de_ier = I915_READ(DEIER); + I915_WRITE(DEIER, de_ier & ~DE_MASTER_IRQ_CONTROL); + (void)I915_READ(DEIER); + de_iir = I915_READ(DEIIR); gt_iir = I915_READ(GTIIR); @@ -290,6 +295,9 @@ irqreturn_t igdng_irq_handler(struct drm_device *dev) gt_iir = new_gt_iir; } + I915_WRITE(DEIER, de_ier); + (void)I915_READ(DEIER); + return ret; } -- cgit v1.2.3-18-g5258 From 5586c8bc93ac5fe75f5fd14e8c7add5344d1c548 Mon Sep 17 00:00:00 2001 From: Zhenyu Wang Date: Fri, 6 Nov 2009 02:13:02 +0000 Subject: drm/i915: Add more registers save/restore for Ironlake suspend Add more display registers save/restore to fix unstable issues during S4 testing on Ironlake. And DPLL_B_MD should not be restored on Ironlake. Signed-off-by: Zhenyu Wang Signed-off-by: Eric Anholt --- drivers/gpu/drm/i915/i915_drv.h | 12 ++++++++++++ drivers/gpu/drm/i915/i915_suspend.c | 36 +++++++++++++++++++++++++++++++++++- 2 files changed, 47 insertions(+), 1 deletion(-) (limited to 'drivers/gpu/drm/i915') diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 57204e29897..a725f659119 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -296,6 +296,7 @@ typedef struct drm_i915_private { u32 saveVBLANK_A; u32 saveVSYNC_A; u32 saveBCLRPAT_A; + u32 saveTRANSACONF; u32 saveTRANS_HTOTAL_A; u32 saveTRANS_HBLANK_A; u32 saveTRANS_HSYNC_A; @@ -326,6 +327,7 @@ typedef struct drm_i915_private { u32 saveVBLANK_B; u32 saveVSYNC_B; u32 saveBCLRPAT_B; + u32 saveTRANSBCONF; u32 saveTRANS_HTOTAL_B; u32 saveTRANS_HBLANK_B; u32 saveTRANS_HSYNC_B; @@ -414,6 +416,16 @@ typedef struct drm_i915_private { u32 savePFB_WIN_SZ; u32 savePFA_WIN_POS; u32 savePFB_WIN_POS; + u32 savePCH_DREF_CONTROL; + u32 saveDISP_ARB_CTL; + u32 savePIPEA_DATA_M1; + u32 savePIPEA_DATA_N1; + u32 savePIPEA_LINK_M1; + u32 savePIPEA_LINK_N1; + u32 savePIPEB_DATA_M1; + u32 savePIPEB_DATA_N1; + u32 savePIPEB_LINK_M1; + u32 savePIPEB_LINK_N1; struct { struct drm_mm gtt_space; diff --git a/drivers/gpu/drm/i915/i915_suspend.c b/drivers/gpu/drm/i915/i915_suspend.c index 992d5617e79..6eec8171a44 100644 --- a/drivers/gpu/drm/i915/i915_suspend.c +++ b/drivers/gpu/drm/i915/i915_suspend.c @@ -239,6 +239,11 @@ static void i915_save_modeset_reg(struct drm_device *dev) if (drm_core_check_feature(dev, DRIVER_MODESET)) return; + if (IS_IGDNG(dev)) { + dev_priv->savePCH_DREF_CONTROL = I915_READ(PCH_DREF_CONTROL); + dev_priv->saveDISP_ARB_CTL = I915_READ(DISP_ARB_CTL); + } + /* Pipe & plane A info */ dev_priv->savePIPEACONF = I915_READ(PIPEACONF); dev_priv->savePIPEASRC = I915_READ(PIPEASRC); @@ -263,6 +268,11 @@ static void i915_save_modeset_reg(struct drm_device *dev) dev_priv->saveBCLRPAT_A = I915_READ(BCLRPAT_A); if (IS_IGDNG(dev)) { + dev_priv->savePIPEA_DATA_M1 = I915_READ(PIPEA_DATA_M1); + dev_priv->savePIPEA_DATA_N1 = I915_READ(PIPEA_DATA_N1); + dev_priv->savePIPEA_LINK_M1 = I915_READ(PIPEA_LINK_M1); + dev_priv->savePIPEA_LINK_N1 = I915_READ(PIPEA_LINK_N1); + dev_priv->saveFDI_TXA_CTL = I915_READ(FDI_TXA_CTL); dev_priv->saveFDI_RXA_CTL = I915_READ(FDI_RXA_CTL); @@ -270,6 +280,7 @@ static void i915_save_modeset_reg(struct drm_device *dev) dev_priv->savePFA_WIN_SZ = I915_READ(PFA_WIN_SZ); dev_priv->savePFA_WIN_POS = I915_READ(PFA_WIN_POS); + dev_priv->saveTRANSACONF = I915_READ(TRANSACONF); dev_priv->saveTRANS_HTOTAL_A = I915_READ(TRANS_HTOTAL_A); dev_priv->saveTRANS_HBLANK_A = I915_READ(TRANS_HBLANK_A); dev_priv->saveTRANS_HSYNC_A = I915_READ(TRANS_HSYNC_A); @@ -314,6 +325,11 @@ static void i915_save_modeset_reg(struct drm_device *dev) dev_priv->saveBCLRPAT_B = I915_READ(BCLRPAT_B); if (IS_IGDNG(dev)) { + dev_priv->savePIPEB_DATA_M1 = I915_READ(PIPEB_DATA_M1); + dev_priv->savePIPEB_DATA_N1 = I915_READ(PIPEB_DATA_N1); + dev_priv->savePIPEB_LINK_M1 = I915_READ(PIPEB_LINK_M1); + dev_priv->savePIPEB_LINK_N1 = I915_READ(PIPEB_LINK_N1); + dev_priv->saveFDI_TXB_CTL = I915_READ(FDI_TXB_CTL); dev_priv->saveFDI_RXB_CTL = I915_READ(FDI_RXB_CTL); @@ -321,6 +337,7 @@ static void i915_save_modeset_reg(struct drm_device *dev) dev_priv->savePFB_WIN_SZ = I915_READ(PFB_WIN_SZ); dev_priv->savePFB_WIN_POS = I915_READ(PFB_WIN_POS); + dev_priv->saveTRANSBCONF = I915_READ(TRANSBCONF); dev_priv->saveTRANS_HTOTAL_B = I915_READ(TRANS_HTOTAL_B); dev_priv->saveTRANS_HBLANK_B = I915_READ(TRANS_HBLANK_B); dev_priv->saveTRANS_HSYNC_B = I915_READ(TRANS_HSYNC_B); @@ -368,6 +385,11 @@ static void i915_restore_modeset_reg(struct drm_device *dev) fpb1_reg = FPB1; } + if (IS_IGDNG(dev)) { + I915_WRITE(PCH_DREF_CONTROL, dev_priv->savePCH_DREF_CONTROL); + I915_WRITE(DISP_ARB_CTL, dev_priv->saveDISP_ARB_CTL); + } + /* Pipe & plane A info */ /* Prime the clock */ if (dev_priv->saveDPLL_A & DPLL_VCO_ENABLE) { @@ -395,6 +417,11 @@ static void i915_restore_modeset_reg(struct drm_device *dev) I915_WRITE(BCLRPAT_A, dev_priv->saveBCLRPAT_A); if (IS_IGDNG(dev)) { + I915_WRITE(PIPEA_DATA_M1, dev_priv->savePIPEA_DATA_M1); + I915_WRITE(PIPEA_DATA_N1, dev_priv->savePIPEA_DATA_N1); + I915_WRITE(PIPEA_LINK_M1, dev_priv->savePIPEA_LINK_M1); + I915_WRITE(PIPEA_LINK_N1, dev_priv->savePIPEA_LINK_N1); + I915_WRITE(FDI_RXA_CTL, dev_priv->saveFDI_RXA_CTL); I915_WRITE(FDI_TXA_CTL, dev_priv->saveFDI_TXA_CTL); @@ -402,6 +429,7 @@ static void i915_restore_modeset_reg(struct drm_device *dev) I915_WRITE(PFA_WIN_SZ, dev_priv->savePFA_WIN_SZ); I915_WRITE(PFA_WIN_POS, dev_priv->savePFA_WIN_POS); + I915_WRITE(TRANSACONF, dev_priv->saveTRANSACONF); I915_WRITE(TRANS_HTOTAL_A, dev_priv->saveTRANS_HTOTAL_A); I915_WRITE(TRANS_HBLANK_A, dev_priv->saveTRANS_HBLANK_A); I915_WRITE(TRANS_HSYNC_A, dev_priv->saveTRANS_HSYNC_A); @@ -439,7 +467,7 @@ static void i915_restore_modeset_reg(struct drm_device *dev) /* Actually enable it */ I915_WRITE(dpll_b_reg, dev_priv->saveDPLL_B); DRM_UDELAY(150); - if (IS_I965G(dev)) + if (IS_I965G(dev) && !IS_IGDNG(dev)) I915_WRITE(DPLL_B_MD, dev_priv->saveDPLL_B_MD); DRM_UDELAY(150); @@ -454,6 +482,11 @@ static void i915_restore_modeset_reg(struct drm_device *dev) I915_WRITE(BCLRPAT_B, dev_priv->saveBCLRPAT_B); if (IS_IGDNG(dev)) { + I915_WRITE(PIPEB_DATA_M1, dev_priv->savePIPEB_DATA_M1); + I915_WRITE(PIPEB_DATA_N1, dev_priv->savePIPEB_DATA_N1); + I915_WRITE(PIPEB_LINK_M1, dev_priv->savePIPEB_LINK_M1); + I915_WRITE(PIPEB_LINK_N1, dev_priv->savePIPEB_LINK_N1); + I915_WRITE(FDI_RXB_CTL, dev_priv->saveFDI_RXB_CTL); I915_WRITE(FDI_TXB_CTL, dev_priv->saveFDI_TXB_CTL); @@ -461,6 +494,7 @@ static void i915_restore_modeset_reg(struct drm_device *dev) I915_WRITE(PFB_WIN_SZ, dev_priv->savePFB_WIN_SZ); I915_WRITE(PFB_WIN_POS, dev_priv->savePFB_WIN_POS); + I915_WRITE(TRANSBCONF, dev_priv->saveTRANSBCONF); I915_WRITE(TRANS_HTOTAL_B, dev_priv->saveTRANS_HTOTAL_B); I915_WRITE(TRANS_HBLANK_B, dev_priv->saveTRANS_HBLANK_B); I915_WRITE(TRANS_HSYNC_B, dev_priv->saveTRANS_HSYNC_B); -- cgit v1.2.3-18-g5258 From 8e9e0eea9955bffbe5e5cd6355157cabddc31f17 Mon Sep 17 00:00:00 2001 From: Zhenyu Wang Date: Wed, 11 Nov 2009 02:30:50 +0000 Subject: drm/i915: Fix CRT hotplug detect by checking really no channels attached For CRT hotplug detect status, we have four test results as blue channel only, green channel only, both blue and green channel, and no channel attached. Origin code only marks both blue and green channel case as connected, but ignore other possible connected states. This one trys to detect CRT by checking no channel attached case instead. Signed-off-by: Zhenyu Wang Signed-off-by: Eric Anholt --- drivers/gpu/drm/i915/intel_crt.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/gpu/drm/i915') diff --git a/drivers/gpu/drm/i915/intel_crt.c b/drivers/gpu/drm/i915/intel_crt.c index 212e22740fc..e5051446c48 100644 --- a/drivers/gpu/drm/i915/intel_crt.c +++ b/drivers/gpu/drm/i915/intel_crt.c @@ -262,8 +262,8 @@ static bool intel_crt_detect_hotplug(struct drm_connector *connector) } while (time_after(timeout, jiffies)); } - if ((I915_READ(PORT_HOTPLUG_STAT) & CRT_HOTPLUG_MONITOR_MASK) == - CRT_HOTPLUG_MONITOR_COLOR) + if ((I915_READ(PORT_HOTPLUG_STAT) & CRT_HOTPLUG_MONITOR_MASK) != + CRT_HOTPLUG_MONITOR_NONE) return true; return false; -- cgit v1.2.3-18-g5258