From 24d05927c37adf62fe8833eceba50585cb78f906 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Fri, 20 Aug 2010 18:08:28 +0200 Subject: drm/i915: unload: fix intel dp encoder cleanup struct intel_dp contains both struct intel_encoder at the beginning (as it's base-class) and an i2c adapater. When initializing, the i2c adapter gets assigned intel_encoder->ddc_adaptor = &intel_dp->adapter and the generic intel_encode_destroy happily calls kfree on this pointer. Ouch. Fix this by using a dp specific cleanup function. Signed-off-by: Daniel Vetter Signed-off-by: Chris Wilson --- drivers/gpu/drm/i915/intel_dp.c | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c index 51d1429..b1fc65b 100644 --- a/drivers/gpu/drm/i915/intel_dp.c +++ b/drivers/gpu/drm/i915/intel_dp.c @@ -1479,6 +1479,15 @@ intel_dp_destroy (struct drm_connector *connector) kfree(connector); } +static void intel_dp_encoder_destroy(struct drm_encoder *encoder) +{ + struct intel_dp *intel_dp = enc_to_intel_dp(encoder); + + i2c_del_adapter(&intel_dp->adapter); + drm_encoder_cleanup(encoder); + kfree(intel_dp); +} + static const struct drm_encoder_helper_funcs intel_dp_helper_funcs = { .dpms = intel_dp_dpms, .mode_fixup = intel_dp_mode_fixup, @@ -1501,7 +1510,7 @@ static const struct drm_connector_helper_funcs intel_dp_connector_helper_funcs = }; static const struct drm_encoder_funcs intel_dp_enc_funcs = { - .destroy = intel_encoder_destroy, + .destroy = intel_dp_encoder_destroy, }; void -- cgit v1.1 From bc0c7f14432f7f94b16f972f2d23b8c1248249b4 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Fri, 20 Aug 2010 18:18:48 +0200 Subject: drm/i915: unload: fix error_work races This is the first patch to clean up module unload races due to outstanding timers/work. Preparatory step: Thou shalt not destroy the workqueue when new work might still get enqued. Now error_work gets queued by the hangcheck timer and only (atomically) reads the chip wedged status. So cancel it right after the hangcheck timer is killed. But the hangcheck is armed by interrupts, so move everything after irqs are disabled. Also change a del_timer to a del_timer_sync in the ums gem code, the hangcheck timer is self-rearming. Signed-off-by: Daniel Vetter Signed-off-by: Chris Wilson --- drivers/gpu/drm/i915/i915_dma.c | 8 +++++--- drivers/gpu/drm/i915/i915_gem.c | 2 +- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_dma.c b/drivers/gpu/drm/i915/i915_dma.c index 9d67b48..736cca8 100644 --- a/drivers/gpu/drm/i915/i915_dma.c +++ b/drivers/gpu/drm/i915/i915_dma.c @@ -2256,9 +2256,6 @@ int i915_driver_unload(struct drm_device *dev) i915_mch_dev = NULL; spin_unlock(&mchdev_lock); - destroy_workqueue(dev_priv->wq); - del_timer_sync(&dev_priv->hangcheck_timer); - io_mapping_free(dev_priv->mm.gtt_mapping); if (dev_priv->mm.gtt_mtrr >= 0) { mtrr_del(dev_priv->mm.gtt_mtrr, dev->agp->base, @@ -2283,6 +2280,9 @@ int i915_driver_unload(struct drm_device *dev) vga_client_register(dev->pdev, NULL, NULL, NULL); } + del_timer_sync(&dev_priv->hangcheck_timer); + cancel_work_sync(&dev_priv->error_work); + if (dev->pdev->msi_enabled) pci_disable_msi(dev->pdev); @@ -2307,6 +2307,8 @@ int i915_driver_unload(struct drm_device *dev) intel_teardown_mchbar(dev); + destroy_workqueue(dev_priv->wq); + pci_dev_put(dev_priv->bridge_dev); kfree(dev->dev_private); diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index 16fca1d..4cccdce 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -4408,7 +4408,7 @@ i915_gem_idle(struct drm_device *dev) * And not confound mm.suspended! */ dev_priv->mm.suspended = 1; - del_timer(&dev_priv->hangcheck_timer); + del_timer_sync(&dev_priv->hangcheck_timer); i915_kernel_lost_context(dev); i915_gem_cleanup_ringbuffer(dev); -- cgit v1.1 From 6c0d93500eb50098e4e35b8b79e073f2f2f5b773 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Fri, 20 Aug 2010 18:26:46 +0200 Subject: drm/i915: unload: fix hotplug_work races hotplug_work is queued by the hotplug interrupt and only either emits a hotplug uevent or queues a crt poll slow-work. No other locking. So it's safe to cancel this work _after_ irq's have been turned off. But before the modesetting objects are destroyed because the hotplug function accesses them (without locking). The current code (for kms) only switches irqs off after modesetting teardown, hence move the irq teardown into the modeset cleanup right before the crtc cleanup. Signed-off-by: Daniel Vetter Signed-off-by: Chris Wilson --- drivers/gpu/drm/i915/i915_dma.c | 2 +- drivers/gpu/drm/i915/intel_display.c | 5 +++++ 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/i915_dma.c b/drivers/gpu/drm/i915/i915_dma.c index 736cca8..45236e7 100644 --- a/drivers/gpu/drm/i915/i915_dma.c +++ b/drivers/gpu/drm/i915/i915_dma.c @@ -2275,7 +2275,7 @@ int i915_driver_unload(struct drm_device *dev) dev_priv->child_dev = NULL; dev_priv->child_dev_num = 0; } - drm_irq_uninstall(dev); + vga_switcheroo_unregister_client(dev->pdev); vga_client_register(dev->pdev, NULL, NULL, NULL); } diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 7c91030..20be935 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -6073,6 +6073,11 @@ void intel_modeset_cleanup(struct drm_device *dev) mutex_unlock(&dev->struct_mutex); + /* Disable the irq before mode object teardown, for the irq might + * enqueue unpin/hotplug work. */ + drm_irq_uninstall(dev); + cancel_work_sync(&dev_priv->hotplug_work); + drm_mode_config_cleanup(dev); } -- cgit v1.1 From a8b4899e4658e53c0c8f4206af105e358e39ee93 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Fri, 20 Aug 2010 21:25:11 +0200 Subject: drm/i915: unload: don't leak error state With kms, interrupts now get disabled in the modesetting cleanup. So free the error state afterwards, it currently gets allocated in the interrupt handler. Signed-off-by: Daniel Vetter Signed-off-by: Chris Wilson --- drivers/gpu/drm/i915/i915_dma.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_dma.c b/drivers/gpu/drm/i915/i915_dma.c index 45236e7..970c338 100644 --- a/drivers/gpu/drm/i915/i915_dma.c +++ b/drivers/gpu/drm/i915/i915_dma.c @@ -2250,8 +2250,6 @@ int i915_driver_unload(struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; - i915_destroy_error_state(dev); - spin_lock(&mchdev_lock); i915_mch_dev = NULL; spin_unlock(&mchdev_lock); @@ -2280,8 +2278,10 @@ int i915_driver_unload(struct drm_device *dev) vga_client_register(dev->pdev, NULL, NULL, NULL); } + /* Free error state after interrupts are fully disabled. */ del_timer_sync(&dev_priv->hangcheck_timer); cancel_work_sync(&dev_priv->error_work); + i915_destroy_error_state(dev); if (dev->pdev->msi_enabled) pci_disable_msi(dev->pdev); -- cgit v1.1 From 3dec0095f71e7d00b7f6180229fd32a2d0a6ce8d Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Fri, 20 Aug 2010 21:40:52 +0200 Subject: drm/i915: unload: fix idle_timer/idle_work races idle_work wasn't cleaned up at all. It takes &dev->struct_mutex, but accesss the mode_config crtc list (without any other locking!). Hence this work needs to be canceled before calling drm_mode_config_cleanup. As evidenced by the kernel's object debuggin code, the current code also cleans up the timer to early (it gets rearmed). So move it right before the final cleanup (it seems to work). Also unconditionally set up the idle_timer in intel_increase_pllclock. If we're unlucky the timer might fire right away, rendering the call in the modesetting teardown pointless. Signed-off-by: Daniel Vetter Signed-off-by: Chris Wilson --- drivers/gpu/drm/i915/intel_display.c | 27 +++++++++++++++------------ 1 file changed, 15 insertions(+), 12 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 20be935..ccfc105 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -43,7 +43,7 @@ bool intel_pipe_has_type (struct drm_crtc *crtc, int type); static void intel_update_watermarks(struct drm_device *dev); -static void intel_increase_pllclock(struct drm_crtc *crtc, bool schedule); +static void intel_increase_pllclock(struct drm_crtc *crtc); static void intel_crtc_update_cursor(struct drm_crtc *crtc); typedef struct { @@ -1527,7 +1527,7 @@ intel_pipe_set_base_atomic(struct drm_crtc *crtc, struct drm_framebuffer *fb, intel_update_fbc(crtc, &crtc->mode); intel_wait_for_vblank(dev, intel_crtc->pipe); - intel_increase_pllclock(crtc, true); + intel_increase_pllclock(crtc); return 0; } @@ -4664,7 +4664,7 @@ static void intel_crtc_idle_timer(unsigned long arg) queue_work(dev_priv->wq, &dev_priv->idle_work); } -static void intel_increase_pllclock(struct drm_crtc *crtc, bool schedule) +static void intel_increase_pllclock(struct drm_crtc *crtc) { struct drm_device *dev = crtc->dev; drm_i915_private_t *dev_priv = dev->dev_private; @@ -4699,9 +4699,8 @@ static void intel_increase_pllclock(struct drm_crtc *crtc, bool schedule) } /* Schedule downclock */ - if (schedule) - mod_timer(&intel_crtc->idle_timer, jiffies + - msecs_to_jiffies(CRTC_IDLE_TIMEOUT)); + mod_timer(&intel_crtc->idle_timer, jiffies + + msecs_to_jiffies(CRTC_IDLE_TIMEOUT)); } static void intel_decrease_pllclock(struct drm_crtc *crtc) @@ -4837,7 +4836,7 @@ void intel_mark_busy(struct drm_device *dev, struct drm_gem_object *obj) I915_WRITE(FW_BLC_SELF, fw_blc_self | FW_BLC_SELF_EN_MASK); } /* Non-busy -> busy, upclock */ - intel_increase_pllclock(crtc, true); + intel_increase_pllclock(crtc); intel_crtc->busy = true; } else { /* Busy -> busy, put off timer */ @@ -6039,12 +6038,9 @@ void intel_modeset_cleanup(struct drm_device *dev) continue; intel_crtc = to_intel_crtc(crtc); - intel_increase_pllclock(crtc, false); - del_timer_sync(&intel_crtc->idle_timer); + intel_increase_pllclock(crtc); } - del_timer_sync(&dev_priv->idle_timer); - if (dev_priv->display.disable_fbc) dev_priv->display.disable_fbc(dev); @@ -6078,10 +6074,17 @@ void intel_modeset_cleanup(struct drm_device *dev) drm_irq_uninstall(dev); cancel_work_sync(&dev_priv->hotplug_work); + /* Shut off idle work before the crtcs get freed. */ + list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { + intel_crtc = to_intel_crtc(crtc); + del_timer_sync(&intel_crtc->idle_timer); + } + del_timer_sync(&dev_priv->idle_timer); + cancel_work_sync(&dev_priv->idle_work); + drm_mode_config_cleanup(dev); } - /* * Return which encoder is currently attached for connector. */ -- cgit v1.1 From 67e77c5ae8bff6f805d207541f1315051248a87b Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Fri, 20 Aug 2010 22:26:30 +0200 Subject: drm/i915: unload: fix unpin_work related races Kill any outstanding unpin_work when destroying the corresponding crtc. Then flush the workqueue before the gem teardown, in case any unpin work is still outstanding. Signed-off-by: Daniel Vetter Signed-off-by: Chris Wilson --- drivers/gpu/drm/i915/i915_dma.c | 3 +++ drivers/gpu/drm/i915/intel_display.c | 14 ++++++++++++++ 2 files changed, 17 insertions(+) diff --git a/drivers/gpu/drm/i915/i915_dma.c b/drivers/gpu/drm/i915/i915_dma.c index 970c338..27a826e 100644 --- a/drivers/gpu/drm/i915/i915_dma.c +++ b/drivers/gpu/drm/i915/i915_dma.c @@ -2292,6 +2292,9 @@ int i915_driver_unload(struct drm_device *dev) intel_opregion_free(dev, 0); if (drm_core_check_feature(dev, DRIVER_MODESET)) { + /* Flush any outstanding unpin_work. */ + flush_workqueue(dev_priv->wq); + i915_gem_free_all_phys_object(dev); mutex_lock(&dev->struct_mutex); diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index ccfc105..794d4ac 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -4850,8 +4850,22 @@ void intel_mark_busy(struct drm_device *dev, struct drm_gem_object *obj) static void intel_crtc_destroy(struct drm_crtc *crtc) { struct intel_crtc *intel_crtc = to_intel_crtc(crtc); + struct drm_device *dev = crtc->dev; + struct intel_unpin_work *work; + unsigned long flags; + + spin_lock_irqsave(&dev->event_lock, flags); + work = intel_crtc->unpin_work; + intel_crtc->unpin_work = NULL; + spin_unlock_irqrestore(&dev->event_lock, flags); + + if (work) { + cancel_work_sync(&work->work); + kfree(work); + } drm_crtc_cleanup(crtc); + kfree(intel_crtc); } -- cgit v1.1 From c911fc1c6ad61b56869ee521f1a477c741b039da Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Fri, 20 Aug 2010 21:23:20 +0200 Subject: drm/i915: unload: ensure that gem is idle When the module unloads, all users should be gone, hence all bo references held by userspace, too. This should already result in an idle ringbuffer. Still, be paranoid and idle gem before starting the unload dance. Also kill the call to i915_gem_lastclose under an if (kms), it's a noop for kms. Signed-off-by: Daniel Vetter Signed-off-by: Chris Wilson --- drivers/gpu/drm/i915/i915_dma.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/i915_dma.c b/drivers/gpu/drm/i915/i915_dma.c index 27a826e..14133eb 100644 --- a/drivers/gpu/drm/i915/i915_dma.c +++ b/drivers/gpu/drm/i915/i915_dma.c @@ -2249,11 +2249,18 @@ free_priv: int i915_driver_unload(struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; + int ret; spin_lock(&mchdev_lock); i915_mch_dev = NULL; spin_unlock(&mchdev_lock); + mutex_lock(&dev->struct_mutex); + ret = i915_gpu_idle(dev); + if (ret) + DRM_ERROR("failed to idle hardware: %d\n", ret); + mutex_unlock(&dev->struct_mutex); + io_mapping_free(dev_priv->mm.gtt_mapping); if (dev_priv->mm.gtt_mtrr >= 0) { mtrr_del(dev_priv->mm.gtt_mtrr, dev->agp->base, @@ -2303,7 +2310,6 @@ int i915_driver_unload(struct drm_device *dev) if (I915_HAS_FBC(dev) && i915_powersave) i915_cleanup_compression(dev); drm_mm_takedown(&dev_priv->vram); - i915_gem_lastclose(dev); intel_cleanup_overlay(dev); } -- cgit v1.1 From 75ef9da2cdb64e7926404dd2b755bbbfe98eaeaf Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Sat, 21 Aug 2010 00:25:16 +0200 Subject: drm/i915: unload: fix retire_work races ums-gem code correctly cancels the retire work (at lastclose time), kms does not do so. Fix this by canceling the work right after ideling the gpu. While staring at the code I noticed that the work function is not static. Fix this, too. Signed-off-by: Daniel Vetter Signed-off-by: Chris Wilson --- drivers/gpu/drm/i915/i915_dma.c | 3 +++ drivers/gpu/drm/i915/i915_drv.h | 1 - drivers/gpu/drm/i915/i915_gem.c | 2 +- 3 files changed, 4 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_dma.c b/drivers/gpu/drm/i915/i915_dma.c index 14133eb..c58ec5c 100644 --- a/drivers/gpu/drm/i915/i915_dma.c +++ b/drivers/gpu/drm/i915/i915_dma.c @@ -2261,6 +2261,9 @@ int i915_driver_unload(struct drm_device *dev) DRM_ERROR("failed to idle hardware: %d\n", ret); mutex_unlock(&dev->struct_mutex); + /* Cancel the retire work handler, which should be idle now. */ + cancel_delayed_work_sync(&dev_priv->mm.retire_work); + io_mapping_free(dev_priv->mm.gtt_mapping); if (dev_priv->mm.gtt_mtrr >= 0) { mtrr_del(dev_priv->mm.gtt_mtrr, dev->agp->base, diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index af4a263..04aada0 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -978,7 +978,6 @@ bool i915_seqno_passed(uint32_t seq1, uint32_t seq2); int i915_gem_object_get_fence_reg(struct drm_gem_object *obj); int i915_gem_object_put_fence_reg(struct drm_gem_object *obj); void i915_gem_retire_requests(struct drm_device *dev); -void i915_gem_retire_work_handler(struct work_struct *work); void i915_gem_clflush_object(struct drm_gem_object *obj); int i915_gem_object_set_domain(struct drm_gem_object *obj, uint32_t read_domains, diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index 4cccdce..26eb6e3 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -1797,7 +1797,7 @@ i915_gem_retire_requests(struct drm_device *dev) i915_gem_retire_requests_ring(dev, &dev_priv->bsd_ring); } -void +static void i915_gem_retire_work_handler(struct work_struct *work) { drm_i915_private_t *dev_priv; -- cgit v1.1 From 481b6af3d1f36d4a19bd36321c1e9f713db49aad Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Mon, 23 Aug 2010 17:43:35 +0100 Subject: drm/i915: Drop the msleep parameter to wait_for() Jesse's feedback from using the wait_for() macro was that the msleep argument was that it was superfluous and made the macro more difficult to use and to read. As the actually amount of time to sleep is not critical, the crucial part is to sleep and let the processor schedule something else whilst we wait for the event, replace the argument with a hardcoded value. Signed-off-by: Chris Wilson Cc: Jesse Barnes --- drivers/gpu/drm/i915/intel_crt.c | 4 ++-- drivers/gpu/drm/i915/intel_display.c | 16 ++++++++-------- drivers/gpu/drm/i915/intel_dp.c | 4 ++-- drivers/gpu/drm/i915/intel_drv.h | 5 ++++- drivers/gpu/drm/i915/intel_lvds.c | 4 ++-- 5 files changed, 18 insertions(+), 15 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_crt.c b/drivers/gpu/drm/i915/intel_crt.c index 4b77351..c2982e4 100644 --- a/drivers/gpu/drm/i915/intel_crt.c +++ b/drivers/gpu/drm/i915/intel_crt.c @@ -187,7 +187,7 @@ static bool intel_ironlake_crt_detect_hotplug(struct drm_connector *connector) I915_WRITE(PCH_ADPA, adpa); if (wait_for((I915_READ(PCH_ADPA) & ADPA_CRT_HOTPLUG_FORCE_TRIGGER) == 0, - 1000, 1)) + 1000)) DRM_ERROR("timed out waiting for FORCE_TRIGGER"); if (turn_off_dac) { @@ -244,7 +244,7 @@ static bool intel_crt_detect_hotplug(struct drm_connector *connector) /* wait for FORCE_DETECT to go off */ if (wait_for((I915_READ(PORT_HOTPLUG_EN) & CRT_HOTPLUG_FORCE_DETECT) == 0, - 1000, 1)) + 1000)) DRM_ERROR("timed out waiting for FORCE_DETECT to go off"); } diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 794d4ac..854d8f4 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -1007,9 +1007,9 @@ void intel_wait_for_vblank(struct drm_device *dev, int pipe) I915_READ(pipestat_reg) | PIPE_VBLANK_INTERRUPT_STATUS); /* Wait for vblank interrupt bit to set */ - if (wait_for((I915_READ(pipestat_reg) & - PIPE_VBLANK_INTERRUPT_STATUS), - 50, 0)) + if (wait_for(I915_READ(pipestat_reg) & + PIPE_VBLANK_INTERRUPT_STATUS, + 50)) DRM_DEBUG_KMS("vblank wait timed out\n"); } @@ -1108,7 +1108,7 @@ void i8xx_disable_fbc(struct drm_device *dev) I915_WRITE(FBC_CONTROL, fbc_ctl); /* Wait for compressing bit to clear */ - if (wait_for((I915_READ(FBC_STATUS) & FBC_STAT_COMPRESSING) == 0, 10, 0)) { + if (wait_for((I915_READ(FBC_STATUS) & FBC_STAT_COMPRESSING) == 0, 10)) { DRM_DEBUG_KMS("FBC idle timed out\n"); return; } @@ -2070,7 +2070,7 @@ static void ironlake_crtc_dpms(struct drm_crtc *crtc, int mode) I915_WRITE(transconf_reg, temp | TRANS_ENABLE); I915_READ(transconf_reg); - if (wait_for(I915_READ(transconf_reg) & TRANS_STATE_ENABLE, 100, 1)) + if (wait_for(I915_READ(transconf_reg) & TRANS_STATE_ENABLE, 100)) DRM_ERROR("failed to enable transcoder\n"); } @@ -2102,7 +2102,7 @@ static void ironlake_crtc_dpms(struct drm_crtc *crtc, int mode) I915_WRITE(pipeconf_reg, temp & ~PIPEACONF_ENABLE); /* wait for cpu pipe off, pipe state */ - if (wait_for((I915_READ(pipeconf_reg) & I965_PIPECONF_ACTIVE) == 0, 50, 1)) + if (wait_for((I915_READ(pipeconf_reg) & I965_PIPECONF_ACTIVE) == 0, 50)) DRM_ERROR("failed to turn off cpu pipe\n"); } else DRM_DEBUG_KMS("crtc %d is disabled\n", pipe); @@ -2160,7 +2160,7 @@ static void ironlake_crtc_dpms(struct drm_crtc *crtc, int mode) I915_WRITE(transconf_reg, temp & ~TRANS_ENABLE); /* wait for PCH transcoder off, transcoder state */ - if (wait_for((I915_READ(transconf_reg) & TRANS_STATE_ENABLE) == 0, 50, 1)) + if (wait_for((I915_READ(transconf_reg) & TRANS_STATE_ENABLE) == 0, 50)) DRM_ERROR("failed to disable transcoder\n"); } @@ -5521,7 +5521,7 @@ void ironlake_enable_drps(struct drm_device *dev) rgvmodectl |= MEMMODE_SWMODE_EN; I915_WRITE(MEMMODECTL, rgvmodectl); - if (wait_for((I915_READ(MEMSWCTL) & MEMCTL_CMD_STS) == 0, 1, 0)) + if (wait_for((I915_READ(MEMSWCTL) & MEMCTL_CMD_STS) == 0, 10)) DRM_ERROR("stuck trying to change perf mode\n"); msleep(1); diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c index b1fc65b..3449a3b 100644 --- a/drivers/gpu/drm/i915/intel_dp.c +++ b/drivers/gpu/drm/i915/intel_dp.c @@ -772,7 +772,7 @@ static void ironlake_edp_panel_on (struct drm_device *dev) pp |= PANEL_UNLOCK_REGS | POWER_TARGET_ON; I915_WRITE(PCH_PP_CONTROL, pp); - if (wait_for(I915_READ(PCH_PP_STATUS) & PP_ON, 5000, 10)) + if (wait_for(I915_READ(PCH_PP_STATUS) & PP_ON, 5000)) DRM_ERROR("panel on wait timed out: 0x%08x\n", I915_READ(PCH_PP_STATUS)); @@ -797,7 +797,7 @@ static void ironlake_edp_panel_off (struct drm_device *dev) pp &= ~POWER_TARGET_ON; I915_WRITE(PCH_PP_CONTROL, pp); - if (wait_for((I915_READ(PCH_PP_STATUS) & PP_ON) == 0, 5000, 10)) + if (wait_for((I915_READ(PCH_PP_STATUS) & PP_ON) == 0, 5000)) DRM_ERROR("panel off wait timed out: 0x%08x\n", I915_READ(PCH_PP_STATUS)); diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index ad312ca..686ed53 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -33,7 +33,7 @@ #include "drm_crtc_helper.h" -#define wait_for(COND, MS, W) ({ \ +#define _wait_for(COND, MS, W) ({ \ unsigned long timeout__ = jiffies + msecs_to_jiffies(MS); \ int ret__ = 0; \ while (! (COND)) { \ @@ -46,6 +46,9 @@ ret__; \ }) +#define wait_for(COND, MS) _wait_for(COND, MS, 1) +#define wait_for_atomic(COND, MS) _wait_for(COND, MS, 0) + /* * Display related stuff */ diff --git a/drivers/gpu/drm/i915/intel_lvds.c b/drivers/gpu/drm/i915/intel_lvds.c index 4fbb016..fe79c5a 100644 --- a/drivers/gpu/drm/i915/intel_lvds.c +++ b/drivers/gpu/drm/i915/intel_lvds.c @@ -114,7 +114,7 @@ static void intel_lvds_set_power(struct drm_device *dev, bool on) I915_WRITE(ctl_reg, I915_READ(ctl_reg) | POWER_TARGET_ON); - if (wait_for(I915_READ(status_reg) & PP_ON, 1000, 0)) + if (wait_for(I915_READ(status_reg) & PP_ON, 1000)) DRM_ERROR("timed out waiting to enable LVDS pipe"); intel_lvds_set_backlight(dev, dev_priv->backlight_duty_cycle); @@ -123,7 +123,7 @@ static void intel_lvds_set_power(struct drm_device *dev, bool on) I915_WRITE(ctl_reg, I915_READ(ctl_reg) & ~POWER_TARGET_ON); - if (wait_for((I915_READ(status_reg) & PP_ON) == 0, 1000, 0)) + if (wait_for((I915_READ(status_reg) & PP_ON) == 0, 1000)) DRM_ERROR("timed out waiting for LVDS pipe to turn off"); I915_WRITE(lvds_reg, I915_READ(lvds_reg) & ~LVDS_PORT_EN); -- cgit v1.1 From 82d7c9e7da9fa11b8ed968c94a19c7732e11c1ad Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Sat, 7 Aug 2010 12:16:25 +0100 Subject: drm/i915: Avoid using msleep under kdb and wait_for() wait_for() uses msleep() to yield the cpu whilst spinning waiting for a register to change. kdb asserts that mode changes are atomic and so prohibits msleep. The alternative would be to use mdelay or to simply probe the register more often instead of busy waiting. Signed-off-by: Chris Wilson --- drivers/gpu/drm/i915/intel_drv.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index 686ed53..1ca3c9e 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -41,7 +41,7 @@ ret__ = -ETIMEDOUT; \ break; \ } \ - if (W) msleep(W); \ + if (W && !in_dbg_master()) msleep(W); \ } \ ret__; \ }) -- cgit v1.1 From 19c55da11660fea1a0f1ddbb33ecf38d4f728799 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Mon, 9 Aug 2010 14:50:53 +0100 Subject: drm/i915/crt: Flush register prior to waiting for vblank. If we don't flush the write then we can not be sure that the border colour will have taken effect by the time we try to read it back. Signed-off-by: Chris Wilson --- drivers/gpu/drm/i915/intel_crt.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/gpu/drm/i915/intel_crt.c b/drivers/gpu/drm/i915/intel_crt.c index c2982e4..6262797 100644 --- a/drivers/gpu/drm/i915/intel_crt.c +++ b/drivers/gpu/drm/i915/intel_crt.c @@ -327,6 +327,7 @@ intel_crt_load_detect(struct drm_crtc *crtc, struct intel_encoder *intel_encoder if (IS_I9XX(dev)) { uint32_t pipeconf = I915_READ(pipeconf_reg); I915_WRITE(pipeconf_reg, pipeconf | PIPECONF_FORCE_BORDER); + POSTING_READ(pipeconf_reg); /* Wait for next Vblank to substitue * border color for Color info */ intel_wait_for_vblank(dev, pipe); -- cgit v1.1 From 3b61796785e7b0ca8846b7a709216dceb6e2f68d Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Tue, 24 Aug 2010 09:02:58 +0100 Subject: drm/i915: Rename i915_opregion.c to intel_opregion.c It's part of the generic Intel driver infrastructure so rename it in prepreparation for using it for VBT. Signed-off-by: Chris Wilson --- drivers/gpu/drm/i915/Makefile | 2 +- drivers/gpu/drm/i915/i915_drv.h | 14 +- drivers/gpu/drm/i915/i915_irq.c | 8 +- drivers/gpu/drm/i915/i915_opregion.c | 562 --------------------------------- drivers/gpu/drm/i915/intel_opregion.c | 563 ++++++++++++++++++++++++++++++++++ 5 files changed, 575 insertions(+), 574 deletions(-) delete mode 100644 drivers/gpu/drm/i915/i915_opregion.c create mode 100644 drivers/gpu/drm/i915/intel_opregion.c diff --git a/drivers/gpu/drm/i915/Makefile b/drivers/gpu/drm/i915/Makefile index 5c8e534..345ca52 100644 --- a/drivers/gpu/drm/i915/Makefile +++ b/drivers/gpu/drm/i915/Makefile @@ -32,7 +32,7 @@ i915-y := i915_drv.o i915_dma.o i915_irq.o i915_mem.o \ dvo_tfp410.o \ dvo_sil164.o -i915-$(CONFIG_ACPI) += i915_opregion.o +i915-$(CONFIG_ACPI) += intel_opregion.o i915-$(CONFIG_COMPAT) += i915_ioc32.o obj-$(CONFIG_DRM_I915) += i915.o diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 04aada0..980061f 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -1054,18 +1054,18 @@ extern int i915_save_state(struct drm_device *dev); extern int i915_restore_state(struct drm_device *dev); #ifdef CONFIG_ACPI -/* i915_opregion.c */ +/* intel_opregion.c */ extern int intel_opregion_init(struct drm_device *dev, int resume); extern void intel_opregion_free(struct drm_device *dev, int suspend); -extern void opregion_asle_intr(struct drm_device *dev); -extern void ironlake_opregion_gse_intr(struct drm_device *dev); -extern void opregion_enable_asle(struct drm_device *dev); +extern void intel_opregion_asle_intr(struct drm_device *dev); +extern void intel_opregion_gse_intr(struct drm_device *dev); +extern void intel_opregion_enable_asle(struct drm_device *dev); #else static inline int intel_opregion_init(struct drm_device *dev, int resume) { return 0; } static inline void intel_opregion_free(struct drm_device *dev, int suspend) { return; } -static inline void opregion_asle_intr(struct drm_device *dev) { return; } -static inline void ironlake_opregion_gse_intr(struct drm_device *dev) { return; } -static inline void opregion_enable_asle(struct drm_device *dev) { return; } +static inline void intel_opregion_asle_intr(struct drm_device *dev) { return; } +static inline void intel_opregion_gse_intr(struct drm_device *dev) { return; } +static inline void intel_opregion_enable_asle(struct drm_device *dev) { return; } #endif /* modesetting */ diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c index 59457e8..3afd6e5 100644 --- a/drivers/gpu/drm/i915/i915_irq.c +++ b/drivers/gpu/drm/i915/i915_irq.c @@ -347,7 +347,7 @@ irqreturn_t ironlake_irq_handler(struct drm_device *dev) if (de_iir & DE_GSE) - ironlake_opregion_gse_intr(dev); + intel_opregion_gse_intr(dev); if (de_iir & DE_PLANEA_FLIP_DONE) { intel_prepare_page_flip(dev, 0); @@ -1065,7 +1065,7 @@ irqreturn_t i915_driver_irq_handler(DRM_IRQ_ARGS) if ((pipea_stats & PIPE_LEGACY_BLC_EVENT_STATUS) || (pipeb_stats & PIPE_LEGACY_BLC_EVENT_STATUS) || (iir & I915_ASLE_INTERRUPT)) - opregion_asle_intr(dev); + intel_opregion_asle_intr(dev); /* With MSI, interrupts are only generated when iir * transitions from zero to nonzero. If another bit got @@ -1252,7 +1252,7 @@ void i915_enable_interrupt (struct drm_device *dev) struct drm_i915_private *dev_priv = dev->dev_private; if (!HAS_PCH_SPLIT(dev)) - opregion_enable_asle(dev); + intel_opregion_enable_asle(dev); dev_priv->irq_enabled = 1; } @@ -1570,7 +1570,7 @@ int i915_driver_irq_postinstall(struct drm_device *dev) I915_WRITE(PORT_HOTPLUG_EN, hotplug_en); } - opregion_enable_asle(dev); + intel_opregion_enable_asle(dev); return 0; } diff --git a/drivers/gpu/drm/i915/i915_opregion.c b/drivers/gpu/drm/i915/i915_opregion.c deleted file mode 100644 index ea5d3fe..0000000 --- a/drivers/gpu/drm/i915/i915_opregion.c +++ /dev/null @@ -1,562 +0,0 @@ -/* - * Copyright 2008 Intel Corporation - * Copyright 2008 Red Hat - * - * Permission is hereby granted, free of charge, to any person obtaining - * a copy of this software and associated documentation files (the - * "Software"), to deal in the Software without restriction, including - * without limitation the rights to use, copy, modify, merge, publish, - * distribute, sub license, and/or sell copies of the Software, and to - * permit persons to whom the Software is furnished to do so, subject to - * the following conditions: - * - * The above copyright notice and this permission notice (including the - * next paragraph) shall be included in all copies or substantial - * portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NON-INFRINGEMENT. IN NO EVENT SHALL INTEL AND/OR ITS SUPPLIERS BE - * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - * - */ - -#include -#include - -#include "drmP.h" -#include "i915_drm.h" -#include "i915_drv.h" - -#define PCI_ASLE 0xe4 -#define PCI_LBPC 0xf4 -#define PCI_ASLS 0xfc - -#define OPREGION_SZ (8*1024) -#define OPREGION_HEADER_OFFSET 0 -#define OPREGION_ACPI_OFFSET 0x100 -#define OPREGION_SWSCI_OFFSET 0x200 -#define OPREGION_ASLE_OFFSET 0x300 -#define OPREGION_VBT_OFFSET 0x1000 - -#define OPREGION_SIGNATURE "IntelGraphicsMem" -#define MBOX_ACPI (1<<0) -#define MBOX_SWSCI (1<<1) -#define MBOX_ASLE (1<<2) - -struct opregion_header { - u8 signature[16]; - u32 size; - u32 opregion_ver; - u8 bios_ver[32]; - u8 vbios_ver[16]; - u8 driver_ver[16]; - u32 mboxes; - u8 reserved[164]; -} __attribute__((packed)); - -/* OpRegion mailbox #1: public ACPI methods */ -struct opregion_acpi { - u32 drdy; /* driver readiness */ - u32 csts; /* notification status */ - u32 cevt; /* current event */ - u8 rsvd1[20]; - u32 didl[8]; /* supported display devices ID list */ - u32 cpdl[8]; /* currently presented display list */ - u32 cadl[8]; /* currently active display list */ - u32 nadl[8]; /* next active devices list */ - u32 aslp; /* ASL sleep time-out */ - u32 tidx; /* toggle table index */ - u32 chpd; /* current hotplug enable indicator */ - u32 clid; /* current lid state*/ - u32 cdck; /* current docking state */ - u32 sxsw; /* Sx state resume */ - u32 evts; /* ASL supported events */ - u32 cnot; /* current OS notification */ - u32 nrdy; /* driver status */ - u8 rsvd2[60]; -} __attribute__((packed)); - -/* OpRegion mailbox #2: SWSCI */ -struct opregion_swsci { - u32 scic; /* SWSCI command|status|data */ - u32 parm; /* command parameters */ - u32 dslp; /* driver sleep time-out */ - u8 rsvd[244]; -} __attribute__((packed)); - -/* OpRegion mailbox #3: ASLE */ -struct opregion_asle { - u32 ardy; /* driver readiness */ - u32 aslc; /* ASLE interrupt command */ - u32 tche; /* technology enabled indicator */ - u32 alsi; /* current ALS illuminance reading */ - u32 bclp; /* backlight brightness to set */ - u32 pfit; /* panel fitting state */ - u32 cblv; /* current brightness level */ - u16 bclm[20]; /* backlight level duty cycle mapping table */ - u32 cpfm; /* current panel fitting mode */ - u32 epfm; /* enabled panel fitting modes */ - u8 plut[74]; /* panel LUT and identifier */ - u32 pfmb; /* PWM freq and min brightness */ - u8 rsvd[102]; -} __attribute__((packed)); - -/* ASLE irq request bits */ -#define ASLE_SET_ALS_ILLUM (1 << 0) -#define ASLE_SET_BACKLIGHT (1 << 1) -#define ASLE_SET_PFIT (1 << 2) -#define ASLE_SET_PWM_FREQ (1 << 3) -#define ASLE_REQ_MSK 0xf - -/* response bits of ASLE irq request */ -#define ASLE_ALS_ILLUM_FAILED (1<<10) -#define ASLE_BACKLIGHT_FAILED (1<<12) -#define ASLE_PFIT_FAILED (1<<14) -#define ASLE_PWM_FREQ_FAILED (1<<16) - -/* ASLE backlight brightness to set */ -#define ASLE_BCLP_VALID (1<<31) -#define ASLE_BCLP_MSK (~(1<<31)) - -/* ASLE panel fitting request */ -#define ASLE_PFIT_VALID (1<<31) -#define ASLE_PFIT_CENTER (1<<0) -#define ASLE_PFIT_STRETCH_TEXT (1<<1) -#define ASLE_PFIT_STRETCH_GFX (1<<2) - -/* PWM frequency and minimum brightness */ -#define ASLE_PFMB_BRIGHTNESS_MASK (0xff) -#define ASLE_PFMB_BRIGHTNESS_VALID (1<<8) -#define ASLE_PFMB_PWM_MASK (0x7ffffe00) -#define ASLE_PFMB_PWM_VALID (1<<31) - -#define ASLE_CBLV_VALID (1<<31) - -#define ACPI_OTHER_OUTPUT (0<<8) -#define ACPI_VGA_OUTPUT (1<<8) -#define ACPI_TV_OUTPUT (2<<8) -#define ACPI_DIGITAL_OUTPUT (3<<8) -#define ACPI_LVDS_OUTPUT (4<<8) - -static u32 asle_set_backlight(struct drm_device *dev, u32 bclp) -{ - struct drm_i915_private *dev_priv = dev->dev_private; - struct opregion_asle *asle = dev_priv->opregion.asle; - u32 blc_pwm_ctl, blc_pwm_ctl2; - u32 max_backlight, level, shift; - - if (!(bclp & ASLE_BCLP_VALID)) - return ASLE_BACKLIGHT_FAILED; - - bclp &= ASLE_BCLP_MSK; - if (bclp < 0 || bclp > 255) - return ASLE_BACKLIGHT_FAILED; - - blc_pwm_ctl = I915_READ(BLC_PWM_CTL); - blc_pwm_ctl2 = I915_READ(BLC_PWM_CTL2); - - if (IS_I965G(dev) && (blc_pwm_ctl2 & BLM_COMBINATION_MODE)) - pci_write_config_dword(dev->pdev, PCI_LBPC, bclp); - else { - if (IS_PINEVIEW(dev)) { - blc_pwm_ctl &= ~(BACKLIGHT_DUTY_CYCLE_MASK - 1); - max_backlight = (blc_pwm_ctl & BACKLIGHT_MODULATION_FREQ_MASK) >> - BACKLIGHT_MODULATION_FREQ_SHIFT; - shift = BACKLIGHT_DUTY_CYCLE_SHIFT + 1; - } else { - blc_pwm_ctl &= ~BACKLIGHT_DUTY_CYCLE_MASK; - max_backlight = ((blc_pwm_ctl & BACKLIGHT_MODULATION_FREQ_MASK) >> - BACKLIGHT_MODULATION_FREQ_SHIFT) * 2; - shift = BACKLIGHT_DUTY_CYCLE_SHIFT; - } - level = (bclp * max_backlight) / 255; - I915_WRITE(BLC_PWM_CTL, blc_pwm_ctl | (level << shift)); - } - asle->cblv = (bclp*0x64)/0xff | ASLE_CBLV_VALID; - - return 0; -} - -static u32 asle_set_als_illum(struct drm_device *dev, u32 alsi) -{ - /* alsi is the current ALS reading in lux. 0 indicates below sensor - range, 0xffff indicates above sensor range. 1-0xfffe are valid */ - return 0; -} - -static u32 asle_set_pwm_freq(struct drm_device *dev, u32 pfmb) -{ - struct drm_i915_private *dev_priv = dev->dev_private; - if (pfmb & ASLE_PFMB_PWM_VALID) { - u32 blc_pwm_ctl = I915_READ(BLC_PWM_CTL); - u32 pwm = pfmb & ASLE_PFMB_PWM_MASK; - blc_pwm_ctl &= BACKLIGHT_DUTY_CYCLE_MASK; - pwm = pwm >> 9; - /* FIXME - what do we do with the PWM? */ - } - return 0; -} - -static u32 asle_set_pfit(struct drm_device *dev, u32 pfit) -{ - /* Panel fitting is currently controlled by the X code, so this is a - noop until modesetting support works fully */ - if (!(pfit & ASLE_PFIT_VALID)) - return ASLE_PFIT_FAILED; - return 0; -} - -void opregion_asle_intr(struct drm_device *dev) -{ - struct drm_i915_private *dev_priv = dev->dev_private; - struct opregion_asle *asle = dev_priv->opregion.asle; - u32 asle_stat = 0; - u32 asle_req; - - if (!asle) - return; - - asle_req = asle->aslc & ASLE_REQ_MSK; - - if (!asle_req) { - DRM_DEBUG_DRIVER("non asle set request??\n"); - return; - } - - if (asle_req & ASLE_SET_ALS_ILLUM) - asle_stat |= asle_set_als_illum(dev, asle->alsi); - - if (asle_req & ASLE_SET_BACKLIGHT) - asle_stat |= asle_set_backlight(dev, asle->bclp); - - if (asle_req & ASLE_SET_PFIT) - asle_stat |= asle_set_pfit(dev, asle->pfit); - - if (asle_req & ASLE_SET_PWM_FREQ) - asle_stat |= asle_set_pwm_freq(dev, asle->pfmb); - - asle->aslc = asle_stat; -} - -static u32 asle_set_backlight_ironlake(struct drm_device *dev, u32 bclp) -{ - struct drm_i915_private *dev_priv = dev->dev_private; - struct opregion_asle *asle = dev_priv->opregion.asle; - u32 cpu_pwm_ctl, pch_pwm_ctl2; - u32 max_backlight, level; - - if (!(bclp & ASLE_BCLP_VALID)) - return ASLE_BACKLIGHT_FAILED; - - bclp &= ASLE_BCLP_MSK; - if (bclp < 0 || bclp > 255) - return ASLE_BACKLIGHT_FAILED; - - cpu_pwm_ctl = I915_READ(BLC_PWM_CPU_CTL); - pch_pwm_ctl2 = I915_READ(BLC_PWM_PCH_CTL2); - /* get the max PWM frequency */ - max_backlight = (pch_pwm_ctl2 >> 16) & BACKLIGHT_DUTY_CYCLE_MASK; - /* calculate the expected PMW frequency */ - level = (bclp * max_backlight) / 255; - /* reserve the high 16 bits */ - cpu_pwm_ctl &= ~(BACKLIGHT_DUTY_CYCLE_MASK); - /* write the updated PWM frequency */ - I915_WRITE(BLC_PWM_CPU_CTL, cpu_pwm_ctl | level); - - asle->cblv = (bclp*0x64)/0xff | ASLE_CBLV_VALID; - - return 0; -} - -void ironlake_opregion_gse_intr(struct drm_device *dev) -{ - struct drm_i915_private *dev_priv = dev->dev_private; - struct opregion_asle *asle = dev_priv->opregion.asle; - u32 asle_stat = 0; - u32 asle_req; - - if (!asle) - return; - - asle_req = asle->aslc & ASLE_REQ_MSK; - - if (!asle_req) { - DRM_DEBUG_DRIVER("non asle set request??\n"); - return; - } - - if (asle_req & ASLE_SET_ALS_ILLUM) { - DRM_DEBUG_DRIVER("Illum is not supported\n"); - asle_stat |= ASLE_ALS_ILLUM_FAILED; - } - - if (asle_req & ASLE_SET_BACKLIGHT) - asle_stat |= asle_set_backlight_ironlake(dev, asle->bclp); - - if (asle_req & ASLE_SET_PFIT) { - DRM_DEBUG_DRIVER("Pfit is not supported\n"); - asle_stat |= ASLE_PFIT_FAILED; - } - - if (asle_req & ASLE_SET_PWM_FREQ) { - DRM_DEBUG_DRIVER("PWM freq is not supported\n"); - asle_stat |= ASLE_PWM_FREQ_FAILED; - } - - asle->aslc = asle_stat; -} -#define ASLE_ALS_EN (1<<0) -#define ASLE_BLC_EN (1<<1) -#define ASLE_PFIT_EN (1<<2) -#define ASLE_PFMB_EN (1<<3) - -void opregion_enable_asle(struct drm_device *dev) -{ - struct drm_i915_private *dev_priv = dev->dev_private; - struct opregion_asle *asle = dev_priv->opregion.asle; - - if (asle) { - if (IS_MOBILE(dev)) { - unsigned long irqflags; - - spin_lock_irqsave(&dev_priv->user_irq_lock, irqflags); - intel_enable_asle(dev); - spin_unlock_irqrestore(&dev_priv->user_irq_lock, - irqflags); - } - - asle->tche = ASLE_ALS_EN | ASLE_BLC_EN | ASLE_PFIT_EN | - ASLE_PFMB_EN; - asle->ardy = 1; - } -} - -#define ACPI_EV_DISPLAY_SWITCH (1<<0) -#define ACPI_EV_LID (1<<1) -#define ACPI_EV_DOCK (1<<2) - -static struct intel_opregion *system_opregion; - -static int intel_opregion_video_event(struct notifier_block *nb, - unsigned long val, void *data) -{ - /* The only video events relevant to opregion are 0x80. These indicate - either a docking event, lid switch or display switch request. In - Linux, these are handled by the dock, button and video drivers. - We might want to fix the video driver to be opregion-aware in - future, but right now we just indicate to the firmware that the - request has been handled */ - - struct opregion_acpi *acpi; - - if (!system_opregion) - return NOTIFY_DONE; - - acpi = system_opregion->acpi; - acpi->csts = 0; - - return NOTIFY_OK; -} - -static struct notifier_block intel_opregion_notifier = { - .notifier_call = intel_opregion_video_event, -}; - -/* - * Initialise the DIDL field in opregion. This passes a list of devices to - * the firmware. Values are defined by section B.4.2 of the ACPI specification - * (version 3) - */ - -static void intel_didl_outputs(struct drm_device *dev) -{ - struct drm_i915_private *dev_priv = dev->dev_private; - struct intel_opregion *opregion = &dev_priv->opregion; - struct drm_connector *connector; - acpi_handle handle; - struct acpi_device *acpi_dev, *acpi_cdev, *acpi_video_bus = NULL; - unsigned long long device_id; - acpi_status status; - int i = 0; - - handle = DEVICE_ACPI_HANDLE(&dev->pdev->dev); - if (!handle || ACPI_FAILURE(acpi_bus_get_device(handle, &acpi_dev))) - return; - - if (acpi_is_video_device(acpi_dev)) - acpi_video_bus = acpi_dev; - else { - list_for_each_entry(acpi_cdev, &acpi_dev->children, node) { - if (acpi_is_video_device(acpi_cdev)) { - acpi_video_bus = acpi_cdev; - break; - } - } - } - - if (!acpi_video_bus) { - printk(KERN_WARNING "No ACPI video bus found\n"); - return; - } - - list_for_each_entry(acpi_cdev, &acpi_video_bus->children, node) { - if (i >= 8) { - dev_printk (KERN_ERR, &dev->pdev->dev, - "More than 8 outputs detected\n"); - return; - } - status = - acpi_evaluate_integer(acpi_cdev->handle, "_ADR", - NULL, &device_id); - if (ACPI_SUCCESS(status)) { - if (!device_id) - goto blind_set; - opregion->acpi->didl[i] = (u32)(device_id & 0x0f0f); - i++; - } - } - -end: - /* If fewer than 8 outputs, the list must be null terminated */ - if (i < 8) - opregion->acpi->didl[i] = 0; - return; - -blind_set: - i = 0; - list_for_each_entry(connector, &dev->mode_config.connector_list, head) { - int output_type = ACPI_OTHER_OUTPUT; - if (i >= 8) { - dev_printk (KERN_ERR, &dev->pdev->dev, - "More than 8 outputs detected\n"); - return; - } - switch (connector->connector_type) { - case DRM_MODE_CONNECTOR_VGA: - case DRM_MODE_CONNECTOR_DVIA: - output_type = ACPI_VGA_OUTPUT; - break; - case DRM_MODE_CONNECTOR_Composite: - case DRM_MODE_CONNECTOR_SVIDEO: - case DRM_MODE_CONNECTOR_Component: - case DRM_MODE_CONNECTOR_9PinDIN: - output_type = ACPI_TV_OUTPUT; - break; - case DRM_MODE_CONNECTOR_DVII: - case DRM_MODE_CONNECTOR_DVID: - case DRM_MODE_CONNECTOR_DisplayPort: - case DRM_MODE_CONNECTOR_HDMIA: - case DRM_MODE_CONNECTOR_HDMIB: - output_type = ACPI_DIGITAL_OUTPUT; - break; - case DRM_MODE_CONNECTOR_LVDS: - output_type = ACPI_LVDS_OUTPUT; - break; - } - opregion->acpi->didl[i] |= (1<<31) | output_type | i; - i++; - } - goto end; -} - -int intel_opregion_init(struct drm_device *dev, int resume) -{ - struct drm_i915_private *dev_priv = dev->dev_private; - struct intel_opregion *opregion = &dev_priv->opregion; - void *base; - u32 asls, mboxes; - int err = 0; - - pci_read_config_dword(dev->pdev, PCI_ASLS, &asls); - DRM_DEBUG_DRIVER("graphic opregion physical addr: 0x%x\n", asls); - if (asls == 0) { - DRM_DEBUG_DRIVER("ACPI OpRegion not supported!\n"); - return -ENOTSUPP; - } - - base = ioremap(asls, OPREGION_SZ); - if (!base) - return -ENOMEM; - - opregion->header = base; - if (memcmp(opregion->header->signature, OPREGION_SIGNATURE, 16)) { - DRM_DEBUG_DRIVER("opregion signature mismatch\n"); - err = -EINVAL; - goto err_out; - } - - mboxes = opregion->header->mboxes; - if (mboxes & MBOX_ACPI) { - DRM_DEBUG_DRIVER("Public ACPI methods supported\n"); - opregion->acpi = base + OPREGION_ACPI_OFFSET; - if (drm_core_check_feature(dev, DRIVER_MODESET)) - intel_didl_outputs(dev); - } else { - DRM_DEBUG_DRIVER("Public ACPI methods not supported\n"); - err = -ENOTSUPP; - goto err_out; - } - opregion->enabled = 1; - - if (mboxes & MBOX_SWSCI) { - DRM_DEBUG_DRIVER("SWSCI supported\n"); - opregion->swsci = base + OPREGION_SWSCI_OFFSET; - } - if (mboxes & MBOX_ASLE) { - DRM_DEBUG_DRIVER("ASLE supported\n"); - opregion->asle = base + OPREGION_ASLE_OFFSET; - opregion_enable_asle(dev); - } - - if (!resume) - acpi_video_register(); - - - /* Notify BIOS we are ready to handle ACPI video ext notifs. - * Right now, all the events are handled by the ACPI video module. - * We don't actually need to do anything with them. */ - opregion->acpi->csts = 0; - opregion->acpi->drdy = 1; - - system_opregion = opregion; - register_acpi_notifier(&intel_opregion_notifier); - - return 0; - -err_out: - iounmap(opregion->header); - opregion->header = NULL; - acpi_video_register(); - return err; -} - -void intel_opregion_free(struct drm_device *dev, int suspend) -{ - struct drm_i915_private *dev_priv = dev->dev_private; - struct intel_opregion *opregion = &dev_priv->opregion; - - if (!opregion->enabled) - return; - - if (!suspend) - acpi_video_unregister(); - - opregion->acpi->drdy = 0; - - system_opregion = NULL; - unregister_acpi_notifier(&intel_opregion_notifier); - - /* just clear all opregion memory pointers now */ - iounmap(opregion->header); - opregion->header = NULL; - opregion->acpi = NULL; - opregion->swsci = NULL; - opregion->asle = NULL; - - opregion->enabled = 0; -} diff --git a/drivers/gpu/drm/i915/intel_opregion.c b/drivers/gpu/drm/i915/intel_opregion.c new file mode 100644 index 0000000..97d5329 --- /dev/null +++ b/drivers/gpu/drm/i915/intel_opregion.c @@ -0,0 +1,563 @@ +/* + * Copyright 2008 Intel Corporation + * Copyright 2008 Red Hat + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sub license, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial + * portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NON-INFRINGEMENT. IN NO EVENT SHALL INTEL AND/OR ITS SUPPLIERS BE + * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +#include +#include + +#include "drmP.h" +#include "i915_drm.h" +#include "i915_drv.h" + +#define PCI_ASLE 0xe4 +#define PCI_LBPC 0xf4 +#define PCI_ASLS 0xfc + +#define OPREGION_SZ (8*1024) +#define OPREGION_HEADER_OFFSET 0 +#define OPREGION_ACPI_OFFSET 0x100 +#define OPREGION_SWSCI_OFFSET 0x200 +#define OPREGION_ASLE_OFFSET 0x300 +#define OPREGION_VBT_OFFSET 0x1000 + +#define OPREGION_SIGNATURE "IntelGraphicsMem" +#define MBOX_ACPI (1<<0) +#define MBOX_SWSCI (1<<1) +#define MBOX_ASLE (1<<2) + +struct opregion_header { + u8 signature[16]; + u32 size; + u32 opregion_ver; + u8 bios_ver[32]; + u8 vbios_ver[16]; + u8 driver_ver[16]; + u32 mboxes; + u8 reserved[164]; +} __attribute__((packed)); + +/* OpRegion mailbox #1: public ACPI methods */ +struct opregion_acpi { + u32 drdy; /* driver readiness */ + u32 csts; /* notification status */ + u32 cevt; /* current event */ + u8 rsvd1[20]; + u32 didl[8]; /* supported display devices ID list */ + u32 cpdl[8]; /* currently presented display list */ + u32 cadl[8]; /* currently active display list */ + u32 nadl[8]; /* next active devices list */ + u32 aslp; /* ASL sleep time-out */ + u32 tidx; /* toggle table index */ + u32 chpd; /* current hotplug enable indicator */ + u32 clid; /* current lid state*/ + u32 cdck; /* current docking state */ + u32 sxsw; /* Sx state resume */ + u32 evts; /* ASL supported events */ + u32 cnot; /* current OS notification */ + u32 nrdy; /* driver status */ + u8 rsvd2[60]; +} __attribute__((packed)); + +/* OpRegion mailbox #2: SWSCI */ +struct opregion_swsci { + u32 scic; /* SWSCI command|status|data */ + u32 parm; /* command parameters */ + u32 dslp; /* driver sleep time-out */ + u8 rsvd[244]; +} __attribute__((packed)); + +/* OpRegion mailbox #3: ASLE */ +struct opregion_asle { + u32 ardy; /* driver readiness */ + u32 aslc; /* ASLE interrupt command */ + u32 tche; /* technology enabled indicator */ + u32 alsi; /* current ALS illuminance reading */ + u32 bclp; /* backlight brightness to set */ + u32 pfit; /* panel fitting state */ + u32 cblv; /* current brightness level */ + u16 bclm[20]; /* backlight level duty cycle mapping table */ + u32 cpfm; /* current panel fitting mode */ + u32 epfm; /* enabled panel fitting modes */ + u8 plut[74]; /* panel LUT and identifier */ + u32 pfmb; /* PWM freq and min brightness */ + u8 rsvd[102]; +} __attribute__((packed)); + +/* ASLE irq request bits */ +#define ASLE_SET_ALS_ILLUM (1 << 0) +#define ASLE_SET_BACKLIGHT (1 << 1) +#define ASLE_SET_PFIT (1 << 2) +#define ASLE_SET_PWM_FREQ (1 << 3) +#define ASLE_REQ_MSK 0xf + +/* response bits of ASLE irq request */ +#define ASLE_ALS_ILLUM_FAILED (1<<10) +#define ASLE_BACKLIGHT_FAILED (1<<12) +#define ASLE_PFIT_FAILED (1<<14) +#define ASLE_PWM_FREQ_FAILED (1<<16) + +/* ASLE backlight brightness to set */ +#define ASLE_BCLP_VALID (1<<31) +#define ASLE_BCLP_MSK (~(1<<31)) + +/* ASLE panel fitting request */ +#define ASLE_PFIT_VALID (1<<31) +#define ASLE_PFIT_CENTER (1<<0) +#define ASLE_PFIT_STRETCH_TEXT (1<<1) +#define ASLE_PFIT_STRETCH_GFX (1<<2) + +/* PWM frequency and minimum brightness */ +#define ASLE_PFMB_BRIGHTNESS_MASK (0xff) +#define ASLE_PFMB_BRIGHTNESS_VALID (1<<8) +#define ASLE_PFMB_PWM_MASK (0x7ffffe00) +#define ASLE_PFMB_PWM_VALID (1<<31) + +#define ASLE_CBLV_VALID (1<<31) + +#define ACPI_OTHER_OUTPUT (0<<8) +#define ACPI_VGA_OUTPUT (1<<8) +#define ACPI_TV_OUTPUT (2<<8) +#define ACPI_DIGITAL_OUTPUT (3<<8) +#define ACPI_LVDS_OUTPUT (4<<8) + +static u32 asle_set_backlight(struct drm_device *dev, u32 bclp) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + struct opregion_asle *asle = dev_priv->opregion.asle; + u32 blc_pwm_ctl, blc_pwm_ctl2; + u32 max_backlight, level, shift; + + if (!(bclp & ASLE_BCLP_VALID)) + return ASLE_BACKLIGHT_FAILED; + + bclp &= ASLE_BCLP_MSK; + if (bclp < 0 || bclp > 255) + return ASLE_BACKLIGHT_FAILED; + + blc_pwm_ctl = I915_READ(BLC_PWM_CTL); + blc_pwm_ctl2 = I915_READ(BLC_PWM_CTL2); + + if (IS_I965G(dev) && (blc_pwm_ctl2 & BLM_COMBINATION_MODE)) + pci_write_config_dword(dev->pdev, PCI_LBPC, bclp); + else { + if (IS_PINEVIEW(dev)) { + blc_pwm_ctl &= ~(BACKLIGHT_DUTY_CYCLE_MASK - 1); + max_backlight = (blc_pwm_ctl & BACKLIGHT_MODULATION_FREQ_MASK) >> + BACKLIGHT_MODULATION_FREQ_SHIFT; + shift = BACKLIGHT_DUTY_CYCLE_SHIFT + 1; + } else { + blc_pwm_ctl &= ~BACKLIGHT_DUTY_CYCLE_MASK; + max_backlight = ((blc_pwm_ctl & BACKLIGHT_MODULATION_FREQ_MASK) >> + BACKLIGHT_MODULATION_FREQ_SHIFT) * 2; + shift = BACKLIGHT_DUTY_CYCLE_SHIFT; + } + level = (bclp * max_backlight) / 255; + I915_WRITE(BLC_PWM_CTL, blc_pwm_ctl | (level << shift)); + } + asle->cblv = (bclp*0x64)/0xff | ASLE_CBLV_VALID; + + return 0; +} + +static u32 asle_set_als_illum(struct drm_device *dev, u32 alsi) +{ + /* alsi is the current ALS reading in lux. 0 indicates below sensor + range, 0xffff indicates above sensor range. 1-0xfffe are valid */ + return 0; +} + +static u32 asle_set_pwm_freq(struct drm_device *dev, u32 pfmb) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + if (pfmb & ASLE_PFMB_PWM_VALID) { + u32 blc_pwm_ctl = I915_READ(BLC_PWM_CTL); + u32 pwm = pfmb & ASLE_PFMB_PWM_MASK; + blc_pwm_ctl &= BACKLIGHT_DUTY_CYCLE_MASK; + pwm = pwm >> 9; + /* FIXME - what do we do with the PWM? */ + } + return 0; +} + +static u32 asle_set_pfit(struct drm_device *dev, u32 pfit) +{ + /* Panel fitting is currently controlled by the X code, so this is a + noop until modesetting support works fully */ + if (!(pfit & ASLE_PFIT_VALID)) + return ASLE_PFIT_FAILED; + return 0; +} + +void intel_opregion_asle_intr(struct drm_device *dev) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + struct opregion_asle *asle = dev_priv->opregion.asle; + u32 asle_stat = 0; + u32 asle_req; + + if (!asle) + return; + + asle_req = asle->aslc & ASLE_REQ_MSK; + + if (!asle_req) { + DRM_DEBUG_DRIVER("non asle set request??\n"); + return; + } + + if (asle_req & ASLE_SET_ALS_ILLUM) + asle_stat |= asle_set_als_illum(dev, asle->alsi); + + if (asle_req & ASLE_SET_BACKLIGHT) + asle_stat |= asle_set_backlight(dev, asle->bclp); + + if (asle_req & ASLE_SET_PFIT) + asle_stat |= asle_set_pfit(dev, asle->pfit); + + if (asle_req & ASLE_SET_PWM_FREQ) + asle_stat |= asle_set_pwm_freq(dev, asle->pfmb); + + asle->aslc = asle_stat; +} + +static u32 asle_set_backlight_ironlake(struct drm_device *dev, u32 bclp) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + struct opregion_asle *asle = dev_priv->opregion.asle; + u32 cpu_pwm_ctl, pch_pwm_ctl2; + u32 max_backlight, level; + + if (!(bclp & ASLE_BCLP_VALID)) + return ASLE_BACKLIGHT_FAILED; + + bclp &= ASLE_BCLP_MSK; + if (bclp < 0 || bclp > 255) + return ASLE_BACKLIGHT_FAILED; + + cpu_pwm_ctl = I915_READ(BLC_PWM_CPU_CTL); + pch_pwm_ctl2 = I915_READ(BLC_PWM_PCH_CTL2); + /* get the max PWM frequency */ + max_backlight = (pch_pwm_ctl2 >> 16) & BACKLIGHT_DUTY_CYCLE_MASK; + /* calculate the expected PMW frequency */ + level = (bclp * max_backlight) / 255; + /* reserve the high 16 bits */ + cpu_pwm_ctl &= ~(BACKLIGHT_DUTY_CYCLE_MASK); + /* write the updated PWM frequency */ + I915_WRITE(BLC_PWM_CPU_CTL, cpu_pwm_ctl | level); + + asle->cblv = (bclp*0x64)/0xff | ASLE_CBLV_VALID; + + return 0; +} + +/* Only present on Ironlake+ */ +void intel_opregion_gse_intr(struct drm_device *dev) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + struct opregion_asle *asle = dev_priv->opregion.asle; + u32 asle_stat = 0; + u32 asle_req; + + if (!asle) + return; + + asle_req = asle->aslc & ASLE_REQ_MSK; + + if (!asle_req) { + DRM_DEBUG_DRIVER("non asle set request??\n"); + return; + } + + if (asle_req & ASLE_SET_ALS_ILLUM) { + DRM_DEBUG_DRIVER("Illum is not supported\n"); + asle_stat |= ASLE_ALS_ILLUM_FAILED; + } + + if (asle_req & ASLE_SET_BACKLIGHT) + asle_stat |= asle_set_backlight_ironlake(dev, asle->bclp); + + if (asle_req & ASLE_SET_PFIT) { + DRM_DEBUG_DRIVER("Pfit is not supported\n"); + asle_stat |= ASLE_PFIT_FAILED; + } + + if (asle_req & ASLE_SET_PWM_FREQ) { + DRM_DEBUG_DRIVER("PWM freq is not supported\n"); + asle_stat |= ASLE_PWM_FREQ_FAILED; + } + + asle->aslc = asle_stat; +} +#define ASLE_ALS_EN (1<<0) +#define ASLE_BLC_EN (1<<1) +#define ASLE_PFIT_EN (1<<2) +#define ASLE_PFMB_EN (1<<3) + +void intel_opregion_enable_asle(struct drm_device *dev) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + struct opregion_asle *asle = dev_priv->opregion.asle; + + if (asle) { + if (IS_MOBILE(dev)) { + unsigned long irqflags; + + spin_lock_irqsave(&dev_priv->user_irq_lock, irqflags); + intel_enable_asle(dev); + spin_unlock_irqrestore(&dev_priv->user_irq_lock, + irqflags); + } + + asle->tche = ASLE_ALS_EN | ASLE_BLC_EN | ASLE_PFIT_EN | + ASLE_PFMB_EN; + asle->ardy = 1; + } +} + +#define ACPI_EV_DISPLAY_SWITCH (1<<0) +#define ACPI_EV_LID (1<<1) +#define ACPI_EV_DOCK (1<<2) + +static struct intel_opregion *system_opregion; + +static int intel_opregion_video_event(struct notifier_block *nb, + unsigned long val, void *data) +{ + /* The only video events relevant to opregion are 0x80. These indicate + either a docking event, lid switch or display switch request. In + Linux, these are handled by the dock, button and video drivers. + We might want to fix the video driver to be opregion-aware in + future, but right now we just indicate to the firmware that the + request has been handled */ + + struct opregion_acpi *acpi; + + if (!system_opregion) + return NOTIFY_DONE; + + acpi = system_opregion->acpi; + acpi->csts = 0; + + return NOTIFY_OK; +} + +static struct notifier_block intel_opregion_notifier = { + .notifier_call = intel_opregion_video_event, +}; + +/* + * Initialise the DIDL field in opregion. This passes a list of devices to + * the firmware. Values are defined by section B.4.2 of the ACPI specification + * (version 3) + */ + +static void intel_didl_outputs(struct drm_device *dev) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + struct intel_opregion *opregion = &dev_priv->opregion; + struct drm_connector *connector; + acpi_handle handle; + struct acpi_device *acpi_dev, *acpi_cdev, *acpi_video_bus = NULL; + unsigned long long device_id; + acpi_status status; + int i = 0; + + handle = DEVICE_ACPI_HANDLE(&dev->pdev->dev); + if (!handle || ACPI_FAILURE(acpi_bus_get_device(handle, &acpi_dev))) + return; + + if (acpi_is_video_device(acpi_dev)) + acpi_video_bus = acpi_dev; + else { + list_for_each_entry(acpi_cdev, &acpi_dev->children, node) { + if (acpi_is_video_device(acpi_cdev)) { + acpi_video_bus = acpi_cdev; + break; + } + } + } + + if (!acpi_video_bus) { + printk(KERN_WARNING "No ACPI video bus found\n"); + return; + } + + list_for_each_entry(acpi_cdev, &acpi_video_bus->children, node) { + if (i >= 8) { + dev_printk (KERN_ERR, &dev->pdev->dev, + "More than 8 outputs detected\n"); + return; + } + status = + acpi_evaluate_integer(acpi_cdev->handle, "_ADR", + NULL, &device_id); + if (ACPI_SUCCESS(status)) { + if (!device_id) + goto blind_set; + opregion->acpi->didl[i] = (u32)(device_id & 0x0f0f); + i++; + } + } + +end: + /* If fewer than 8 outputs, the list must be null terminated */ + if (i < 8) + opregion->acpi->didl[i] = 0; + return; + +blind_set: + i = 0; + list_for_each_entry(connector, &dev->mode_config.connector_list, head) { + int output_type = ACPI_OTHER_OUTPUT; + if (i >= 8) { + dev_printk (KERN_ERR, &dev->pdev->dev, + "More than 8 outputs detected\n"); + return; + } + switch (connector->connector_type) { + case DRM_MODE_CONNECTOR_VGA: + case DRM_MODE_CONNECTOR_DVIA: + output_type = ACPI_VGA_OUTPUT; + break; + case DRM_MODE_CONNECTOR_Composite: + case DRM_MODE_CONNECTOR_SVIDEO: + case DRM_MODE_CONNECTOR_Component: + case DRM_MODE_CONNECTOR_9PinDIN: + output_type = ACPI_TV_OUTPUT; + break; + case DRM_MODE_CONNECTOR_DVII: + case DRM_MODE_CONNECTOR_DVID: + case DRM_MODE_CONNECTOR_DisplayPort: + case DRM_MODE_CONNECTOR_HDMIA: + case DRM_MODE_CONNECTOR_HDMIB: + output_type = ACPI_DIGITAL_OUTPUT; + break; + case DRM_MODE_CONNECTOR_LVDS: + output_type = ACPI_LVDS_OUTPUT; + break; + } + opregion->acpi->didl[i] |= (1<<31) | output_type | i; + i++; + } + goto end; +} + +int intel_opregion_init(struct drm_device *dev, int resume) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + struct intel_opregion *opregion = &dev_priv->opregion; + void *base; + u32 asls, mboxes; + int err = 0; + + pci_read_config_dword(dev->pdev, PCI_ASLS, &asls); + DRM_DEBUG_DRIVER("graphic opregion physical addr: 0x%x\n", asls); + if (asls == 0) { + DRM_DEBUG_DRIVER("ACPI OpRegion not supported!\n"); + return -ENOTSUPP; + } + + base = ioremap(asls, OPREGION_SZ); + if (!base) + return -ENOMEM; + + opregion->header = base; + if (memcmp(opregion->header->signature, OPREGION_SIGNATURE, 16)) { + DRM_DEBUG_DRIVER("opregion signature mismatch\n"); + err = -EINVAL; + goto err_out; + } + + mboxes = opregion->header->mboxes; + if (mboxes & MBOX_ACPI) { + DRM_DEBUG_DRIVER("Public ACPI methods supported\n"); + opregion->acpi = base + OPREGION_ACPI_OFFSET; + if (drm_core_check_feature(dev, DRIVER_MODESET)) + intel_didl_outputs(dev); + } else { + DRM_DEBUG_DRIVER("Public ACPI methods not supported\n"); + err = -ENOTSUPP; + goto err_out; + } + opregion->enabled = 1; + + if (mboxes & MBOX_SWSCI) { + DRM_DEBUG_DRIVER("SWSCI supported\n"); + opregion->swsci = base + OPREGION_SWSCI_OFFSET; + } + if (mboxes & MBOX_ASLE) { + DRM_DEBUG_DRIVER("ASLE supported\n"); + opregion->asle = base + OPREGION_ASLE_OFFSET; + intel_opregion_enable_asle(dev); + } + + if (!resume) + acpi_video_register(); + + + /* Notify BIOS we are ready to handle ACPI video ext notifs. + * Right now, all the events are handled by the ACPI video module. + * We don't actually need to do anything with them. */ + opregion->acpi->csts = 0; + opregion->acpi->drdy = 1; + + system_opregion = opregion; + register_acpi_notifier(&intel_opregion_notifier); + + return 0; + +err_out: + iounmap(opregion->header); + opregion->header = NULL; + acpi_video_register(); + return err; +} + +void intel_opregion_free(struct drm_device *dev, int suspend) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + struct intel_opregion *opregion = &dev_priv->opregion; + + if (!opregion->enabled) + return; + + if (!suspend) + acpi_video_unregister(); + + opregion->acpi->drdy = 0; + + system_opregion = NULL; + unregister_acpi_notifier(&intel_opregion_notifier); + + /* just clear all opregion memory pointers now */ + iounmap(opregion->header); + opregion->header = NULL; + opregion->acpi = NULL; + opregion->swsci = NULL; + opregion->asle = NULL; + + opregion->enabled = 0; +} -- cgit v1.1 From 44834a67c0082e2cf74b16be91e49108b1432d65 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Thu, 19 Aug 2010 16:09:23 +0100 Subject: drm/i915: Use the VBT from OpRegion when available (v3) It is recommended that we use the Video BIOS tables that were copied into the OpRegion during POST when initialising the driver. This saves us from having to furtle around inside the ROM ourselves and possibly allows the vBIOS to adjust the tables prior to initialisation. On some systems, such as the Samsung N210, there is no accessible VBIOS and the only means of finding the VBT is through the OpRegion. v2: Rearrange the code so that ASLE is enabled along with ACPI v3: Enable OpRegion parsing even without ACPI Signed-off-by: Chris Wilson Cc: Matthew Garrett --- drivers/gpu/drm/i915/Makefile | 2 +- drivers/gpu/drm/i915/i915_debugfs.c | 21 +++++++ drivers/gpu/drm/i915/i915_dma.c | 9 ++- drivers/gpu/drm/i915/i915_drv.c | 7 ++- drivers/gpu/drm/i915/i915_drv.h | 14 +++-- drivers/gpu/drm/i915/intel_bios.c | 73 ++++++++++++---------- drivers/gpu/drm/i915/intel_opregion.c | 113 +++++++++++++++++----------------- 7 files changed, 141 insertions(+), 98 deletions(-) diff --git a/drivers/gpu/drm/i915/Makefile b/drivers/gpu/drm/i915/Makefile index 345ca52..f6e98dd 100644 --- a/drivers/gpu/drm/i915/Makefile +++ b/drivers/gpu/drm/i915/Makefile @@ -26,13 +26,13 @@ i915-y := i915_drv.o i915_dma.o i915_irq.o i915_mem.o \ intel_dvo.o \ intel_ringbuffer.o \ intel_overlay.o \ + intel_opregion.o \ dvo_ch7xxx.o \ dvo_ch7017.o \ dvo_ivch.o \ dvo_tfp410.o \ dvo_sil164.o -i915-$(CONFIG_ACPI) += intel_opregion.o i915-$(CONFIG_COMPAT) += i915_ioc32.o obj-$(CONFIG_DRM_I915) += i915.o diff --git a/drivers/gpu/drm/i915/i915_debugfs.c b/drivers/gpu/drm/i915/i915_debugfs.c index 5e43d70..16133f1 100644 --- a/drivers/gpu/drm/i915/i915_debugfs.c +++ b/drivers/gpu/drm/i915/i915_debugfs.c @@ -718,6 +718,26 @@ static int i915_gfxec(struct seq_file *m, void *unused) return 0; } +static int i915_opregion(struct seq_file *m, void *unused) +{ + struct drm_info_node *node = (struct drm_info_node *) m->private; + struct drm_device *dev = node->minor->dev; + drm_i915_private_t *dev_priv = dev->dev_private; + struct intel_opregion *opregion = &dev_priv->opregion; + int ret; + + ret = mutex_lock_interruptible(&dev->struct_mutex); + if (ret) + return ret; + + if (opregion->header) + seq_write(m, opregion->header, OPREGION_SIZE); + + mutex_unlock(&dev->struct_mutex); + + return 0; +} + static int i915_wedged_open(struct inode *inode, struct file *filp) @@ -845,6 +865,7 @@ static struct drm_info_list i915_debugfs_list[] = { {"i915_gfxec", i915_gfxec, 0}, {"i915_fbc_status", i915_fbc_status, 0}, {"i915_sr_status", i915_sr_status, 0}, + {"i915_opregion", i915_opregion, 0}, }; #define I915_DEBUGFS_ENTRIES ARRAY_SIZE(i915_debugfs_list) diff --git a/drivers/gpu/drm/i915/i915_dma.c b/drivers/gpu/drm/i915/i915_dma.c index c58ec5c..2dae3be9 100644 --- a/drivers/gpu/drm/i915/i915_dma.c +++ b/drivers/gpu/drm/i915/i915_dma.c @@ -40,6 +40,7 @@ #include #include #include +#include extern int intel_max_stolen; /* from AGP driver */ @@ -2166,6 +2167,7 @@ int i915_driver_load(struct drm_device *dev, unsigned long flags) /* Try to make sure MCHBAR is enabled before poking at it */ intel_setup_mchbar(dev); + intel_opregion_setup(dev); i915_gem_load(dev); @@ -2221,7 +2223,8 @@ int i915_driver_load(struct drm_device *dev, unsigned long flags) } /* Must be done after probing outputs */ - intel_opregion_init(dev, 0); + intel_opregion_init(dev); + acpi_video_register(); setup_timer(&dev_priv->hangcheck_timer, i915_hangcheck_elapsed, (unsigned long) dev); @@ -2271,6 +2274,8 @@ int i915_driver_unload(struct drm_device *dev) dev_priv->mm.gtt_mtrr = -1; } + acpi_video_unregister(); + if (drm_core_check_feature(dev, DRIVER_MODESET)) { intel_modeset_cleanup(dev); @@ -2299,7 +2304,7 @@ int i915_driver_unload(struct drm_device *dev) if (dev_priv->regs != NULL) iounmap(dev_priv->regs); - intel_opregion_free(dev, 0); + intel_opregion_fini(dev); if (drm_core_check_feature(dev, DRIVER_MODESET)) { /* Flush any outstanding unpin_work. */ diff --git a/drivers/gpu/drm/i915/i915_drv.c b/drivers/gpu/drm/i915/i915_drv.c index ba75255..2879a76 100644 --- a/drivers/gpu/drm/i915/i915_drv.c +++ b/drivers/gpu/drm/i915/i915_drv.c @@ -236,7 +236,7 @@ static int i915_drm_freeze(struct drm_device *dev) i915_save_state(dev); - intel_opregion_free(dev, 1); + intel_opregion_fini(dev); /* Modeset on resume, not lid events */ dev_priv->modeset_on_lid = 0; @@ -276,8 +276,7 @@ static int i915_drm_thaw(struct drm_device *dev) int error = 0; i915_restore_state(dev); - - intel_opregion_init(dev, 1); + intel_opregion_setup(dev); /* KMS EnterVT equivalent */ if (drm_core_check_feature(dev, DRIVER_MODESET)) { @@ -293,6 +292,8 @@ static int i915_drm_thaw(struct drm_device *dev) drm_helper_resume_force_mode(dev); } + intel_opregion_init(dev); + dev_priv->modeset_on_lid = 0; return error; diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 980061f..f6940f1 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -110,8 +110,9 @@ struct intel_opregion { struct opregion_acpi *acpi; struct opregion_swsci *swsci; struct opregion_asle *asle; - int enabled; + void *vbt; }; +#define OPREGION_SIZE (8*1024) struct intel_overlay; struct intel_overlay_error_state; @@ -1053,16 +1054,17 @@ extern int i915_restore_state(struct drm_device *dev); extern int i915_save_state(struct drm_device *dev); extern int i915_restore_state(struct drm_device *dev); -#ifdef CONFIG_ACPI /* intel_opregion.c */ -extern int intel_opregion_init(struct drm_device *dev, int resume); -extern void intel_opregion_free(struct drm_device *dev, int suspend); +extern int intel_opregion_setup(struct drm_device *dev); +#ifdef CONFIG_ACPI +extern void intel_opregion_init(struct drm_device *dev); +extern void intel_opregion_fini(struct drm_device *dev); extern void intel_opregion_asle_intr(struct drm_device *dev); extern void intel_opregion_gse_intr(struct drm_device *dev); extern void intel_opregion_enable_asle(struct drm_device *dev); #else -static inline int intel_opregion_init(struct drm_device *dev, int resume) { return 0; } -static inline void intel_opregion_free(struct drm_device *dev, int suspend) { return; } +static inline void intel_opregion_init(struct drm_device *dev) { return; } +static inline void intel_opregion_fini(struct drm_device *dev) { return; } static inline void intel_opregion_asle_intr(struct drm_device *dev) { return; } static inline void intel_opregion_gse_intr(struct drm_device *dev) { return; } static inline void intel_opregion_enable_asle(struct drm_device *dev) { return; } diff --git a/drivers/gpu/drm/i915/intel_bios.c b/drivers/gpu/drm/i915/intel_bios.c index 96f75d7..8d7deca 100644 --- a/drivers/gpu/drm/i915/intel_bios.c +++ b/drivers/gpu/drm/i915/intel_bios.c @@ -317,7 +317,7 @@ parse_general_definitions(struct drm_i915_private *dev_priv, static void parse_sdvo_device_mapping(struct drm_i915_private *dev_priv, - struct bdb_header *bdb) + struct bdb_header *bdb) { struct sdvo_device_mapping *p_mapping; struct bdb_general_definitions *p_defs; @@ -327,7 +327,7 @@ parse_sdvo_device_mapping(struct drm_i915_private *dev_priv, p_defs = find_section(bdb, BDB_GENERAL_DEFINITIONS); if (!p_defs) { - DRM_DEBUG_KMS("No general definition block is found\n"); + DRM_DEBUG_KMS("No general definition block is found, unable to construct sdvo mapping.\n"); return; } /* judge whether the size of child device meets the requirements. @@ -460,7 +460,7 @@ parse_device_mapping(struct drm_i915_private *dev_priv, p_defs = find_section(bdb, BDB_GENERAL_DEFINITIONS); if (!p_defs) { - DRM_DEBUG_KMS("No general definition block is found\n"); + DRM_DEBUG_KMS("No general definition block is found, no devices defined.\n"); return; } /* judge whether the size of child device meets the requirements. @@ -513,6 +513,7 @@ parse_device_mapping(struct drm_i915_private *dev_priv, } return; } + /** * intel_init_bios - initialize VBIOS settings & find VBT * @dev: DRM device @@ -520,11 +521,6 @@ parse_device_mapping(struct drm_i915_private *dev_priv, * Loads the Video BIOS and checks that the VBT exists. Sets scratch registers * to appropriate values. * - * VBT existence is a sanity check that is relied on by other i830_bios.c code. - * Note that it would be better to use a BIOS call to get the VBT, as BIOSes may - * feed an updated VBT back through that, compared to what we'll fetch using - * this method of groping around in the BIOS data. - * * Returns 0 on success, nonzero on failure. */ bool @@ -532,31 +528,45 @@ intel_init_bios(struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; struct pci_dev *pdev = dev->pdev; - struct vbt_header *vbt = NULL; - struct bdb_header *bdb; - u8 __iomem *bios; - size_t size; - int i; - - bios = pci_map_rom(pdev, &size); - if (!bios) - return -1; - - /* Scour memory looking for the VBT signature */ - for (i = 0; i + 4 < size; i++) { - if (!memcmp(bios + i, "$VBT", 4)) { - vbt = (struct vbt_header *)(bios + i); - break; - } + struct bdb_header *bdb = NULL; + u8 __iomem *bios = NULL; + + /* XXX Should this validation be moved to intel_opregion.c? */ + if (dev_priv->opregion.vbt) { + struct vbt_header *vbt = dev_priv->opregion.vbt; + if (memcmp(vbt->signature, "$VBT", 4) == 0) { + DRM_DEBUG_DRIVER("Using VBT from OpRegion: %20s\n", + vbt->signature); + bdb = (struct bdb_header *)((char *)vbt + vbt->bdb_offset); + } else + dev_priv->opregion.vbt = NULL; } - if (!vbt) { - DRM_ERROR("VBT signature missing\n"); - pci_unmap_rom(pdev, bios); - return -1; - } + if (bdb == NULL) { + struct vbt_header *vbt = NULL; + size_t size; + int i; - bdb = (struct bdb_header *)(bios + i + vbt->bdb_offset); + bios = pci_map_rom(pdev, &size); + if (!bios) + return -1; + + /* Scour memory looking for the VBT signature */ + for (i = 0; i + 4 < size; i++) { + if (!memcmp(bios + i, "$VBT", 4)) { + vbt = (struct vbt_header *)(bios + i); + break; + } + } + + if (!vbt) { + DRM_ERROR("VBT signature missing\n"); + pci_unmap_rom(pdev, bios); + return -1; + } + + bdb = (struct bdb_header *)(bios + i + vbt->bdb_offset); + } /* Grab useful general definitions */ parse_general_features(dev_priv, bdb); @@ -568,7 +578,8 @@ intel_init_bios(struct drm_device *dev) parse_driver_features(dev_priv, bdb); parse_edp(dev_priv, bdb); - pci_unmap_rom(pdev, bios); + if (bios) + pci_unmap_rom(pdev, bios); return 0; } diff --git a/drivers/gpu/drm/i915/intel_opregion.c b/drivers/gpu/drm/i915/intel_opregion.c index 97d5329..3cb1323 100644 --- a/drivers/gpu/drm/i915/intel_opregion.c +++ b/drivers/gpu/drm/i915/intel_opregion.c @@ -36,12 +36,11 @@ #define PCI_LBPC 0xf4 #define PCI_ASLS 0xfc -#define OPREGION_SZ (8*1024) #define OPREGION_HEADER_OFFSET 0 #define OPREGION_ACPI_OFFSET 0x100 #define OPREGION_SWSCI_OFFSET 0x200 #define OPREGION_ASLE_OFFSET 0x300 -#define OPREGION_VBT_OFFSET 0x1000 +#define OPREGION_VBT_OFFSET 0x400 #define OPREGION_SIGNATURE "IntelGraphicsMem" #define MBOX_ACPI (1<<0) @@ -143,6 +142,7 @@ struct opregion_asle { #define ACPI_DIGITAL_OUTPUT (3<<8) #define ACPI_LVDS_OUTPUT (4<<8) +#ifdef CONFIG_ACPI static u32 asle_set_backlight(struct drm_device *dev, u32 bclp) { struct drm_i915_private *dev_priv = dev->dev_private; @@ -465,7 +465,58 @@ blind_set: goto end; } -int intel_opregion_init(struct drm_device *dev, int resume) +void intel_opregion_init(struct drm_device *dev) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + struct intel_opregion *opregion = &dev_priv->opregion; + + if (!opregion->header) + return; + + if (opregion->acpi) { + if (drm_core_check_feature(dev, DRIVER_MODESET)) + intel_didl_outputs(dev); + + /* Notify BIOS we are ready to handle ACPI video ext notifs. + * Right now, all the events are handled by the ACPI video module. + * We don't actually need to do anything with them. */ + opregion->acpi->csts = 0; + opregion->acpi->drdy = 1; + + system_opregion = opregion; + register_acpi_notifier(&intel_opregion_notifier); + } + + if (opregion->asle) + intel_opregion_enable_asle(dev); +} + +void intel_opregion_fini(struct drm_device *dev) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + struct intel_opregion *opregion = &dev_priv->opregion; + + if (!opregion->header) + return; + + if (opregion->acpi) { + opregion->acpi->drdy = 0; + + system_opregion = NULL; + unregister_acpi_notifier(&intel_opregion_notifier); + } + + /* just clear all opregion memory pointers now */ + iounmap(opregion->header); + opregion->header = NULL; + opregion->acpi = NULL; + opregion->swsci = NULL; + opregion->asle = NULL; + opregion->vbt = NULL; +} +#endif + +int intel_opregion_setup(struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; struct intel_opregion *opregion = &dev_priv->opregion; @@ -480,29 +531,23 @@ int intel_opregion_init(struct drm_device *dev, int resume) return -ENOTSUPP; } - base = ioremap(asls, OPREGION_SZ); + base = ioremap(asls, OPREGION_SIZE); if (!base) return -ENOMEM; - opregion->header = base; - if (memcmp(opregion->header->signature, OPREGION_SIGNATURE, 16)) { + if (memcmp(base, OPREGION_SIGNATURE, 16)) { DRM_DEBUG_DRIVER("opregion signature mismatch\n"); err = -EINVAL; goto err_out; } + opregion->header = base; + opregion->vbt = base + OPREGION_VBT_OFFSET; mboxes = opregion->header->mboxes; if (mboxes & MBOX_ACPI) { DRM_DEBUG_DRIVER("Public ACPI methods supported\n"); opregion->acpi = base + OPREGION_ACPI_OFFSET; - if (drm_core_check_feature(dev, DRIVER_MODESET)) - intel_didl_outputs(dev); - } else { - DRM_DEBUG_DRIVER("Public ACPI methods not supported\n"); - err = -ENOTSUPP; - goto err_out; } - opregion->enabled = 1; if (mboxes & MBOX_SWSCI) { DRM_DEBUG_DRIVER("SWSCI supported\n"); @@ -511,53 +556,11 @@ int intel_opregion_init(struct drm_device *dev, int resume) if (mboxes & MBOX_ASLE) { DRM_DEBUG_DRIVER("ASLE supported\n"); opregion->asle = base + OPREGION_ASLE_OFFSET; - intel_opregion_enable_asle(dev); } - if (!resume) - acpi_video_register(); - - - /* Notify BIOS we are ready to handle ACPI video ext notifs. - * Right now, all the events are handled by the ACPI video module. - * We don't actually need to do anything with them. */ - opregion->acpi->csts = 0; - opregion->acpi->drdy = 1; - - system_opregion = opregion; - register_acpi_notifier(&intel_opregion_notifier); - return 0; err_out: iounmap(opregion->header); - opregion->header = NULL; - acpi_video_register(); return err; } - -void intel_opregion_free(struct drm_device *dev, int suspend) -{ - struct drm_i915_private *dev_priv = dev->dev_private; - struct intel_opregion *opregion = &dev_priv->opregion; - - if (!opregion->enabled) - return; - - if (!suspend) - acpi_video_unregister(); - - opregion->acpi->drdy = 0; - - system_opregion = NULL; - unregister_acpi_notifier(&intel_opregion_notifier); - - /* just clear all opregion memory pointers now */ - iounmap(opregion->header); - opregion->header = NULL; - opregion->acpi = NULL; - opregion->swsci = NULL; - opregion->asle = NULL; - - opregion->enabled = 0; -} -- cgit v1.1 From 425904dd8a86d9ca3a3be38eaaa12b4844dceed6 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Sun, 22 Aug 2010 18:21:42 +0100 Subject: drm/i915: Addin-offset is an unreliable indicator of LVDS presence (v2) My Samsung N210 has a VBT with DEVICE_TYPE_INT_LFP with a zero addin-offset. With the check in place, the panel was declared absent. v2: Only trust BIOS writers that have graduated to writing OpRegions. (We are all doomed.) Signed-off-by: Chris Wilson Cc: Zhao Yakui Cc: Adam Jackson Reviewed-by: Adam Jackson --- drivers/gpu/drm/i915/intel_lvds.c | 46 ++++++++++++++++++++++----------------- 1 file changed, 26 insertions(+), 20 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_lvds.c b/drivers/gpu/drm/i915/intel_lvds.c index fe79c5a..047bd95 100644 --- a/drivers/gpu/drm/i915/intel_lvds.c +++ b/drivers/gpu/drm/i915/intel_lvds.c @@ -777,38 +777,44 @@ static void intel_find_lvds_downclock(struct drm_device *dev, * If it is present, return 1. * If it is not present, return false. * If no child dev is parsed from VBT, it assumes that the LVDS is present. - * Note: The addin_offset should also be checked for LVDS panel. - * Only when it is non-zero, it is assumed that it is present. */ -static int lvds_is_present_in_vbt(struct drm_device *dev) +static bool lvds_is_present_in_vbt(struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; - struct child_device_config *p_child; - int i, ret; + int i; if (!dev_priv->child_dev_num) - return 1; + return true; - ret = 0; for (i = 0; i < dev_priv->child_dev_num; i++) { - p_child = dev_priv->child_dev + i; - /* - * If the device type is not LFP, continue. - * If the device type is 0x22, it is also regarded as LFP. + struct child_device_config *child = dev_priv->child_dev + i; + + /* If the device type is not LFP, continue. + * We have to check both the new identifiers as well as the + * old for compatibility with some BIOSes. */ - if (p_child->device_type != DEVICE_TYPE_INT_LFP && - p_child->device_type != DEVICE_TYPE_LFP) + if (child->device_type != DEVICE_TYPE_INT_LFP && + child->device_type != DEVICE_TYPE_LFP) continue; - /* The addin_offset should be checked. Only when it is - * non-zero, it is regarded as present. + /* However, we cannot trust the BIOS writers to populate + * the VBT correctly. Since LVDS requires additional + * information from AIM blocks, a non-zero addin offset is + * a good indicator that the LVDS is actually present. */ - if (p_child->addin_offset) { - ret = 1; - break; - } + if (child->addin_offset) + return true; + + /* But even then some BIOS writers perform some black magic + * and instantiate the device without reference to any + * additional data. Trust that if the VBT was written into + * the OpRegion then they have validated the LVDS's existence. + */ + if (dev_priv->opregion.vbt) + return true; } - return ret; + + return false; } /** -- cgit v1.1 From 2bbda389632dd810d80c055fc1ec90827a16f687 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Thu, 2 Sep 2010 17:59:39 +0100 Subject: drm/i915: Ironlake page-flipping is per-plane not per-pipe Fix a minor confusion between intel_page_flip_finish(pipe) and intel_page_flip_finish_plane(plane) -- should have no effect as currently we map pipe 0 to plane 0 (and pipe 1 to plane 1). Signed-off-by: Chris Wilson --- drivers/gpu/drm/i915/i915_irq.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c index 3afd6e5..e797157 100644 --- a/drivers/gpu/drm/i915/i915_irq.c +++ b/drivers/gpu/drm/i915/i915_irq.c @@ -351,12 +351,12 @@ irqreturn_t ironlake_irq_handler(struct drm_device *dev) if (de_iir & DE_PLANEA_FLIP_DONE) { intel_prepare_page_flip(dev, 0); - intel_finish_page_flip(dev, 0); + intel_finish_page_flip_plane(dev, 0); } if (de_iir & DE_PLANEB_FLIP_DONE) { intel_prepare_page_flip(dev, 1); - intel_finish_page_flip(dev, 1); + intel_finish_page_flip_plane(dev, 1); } if (de_iir & DE_PIPEA_VBLANK) -- cgit v1.1 From efe8c25680fcd3548142f956dcd02d5fdaf3f159 Mon Sep 17 00:00:00 2001 From: Sitsofe Wheeler Date: Tue, 24 Aug 2010 16:56:16 +0100 Subject: drm/i915: Revert extra intel_wait_for_vblank to prevent stalls. With the extra intel_wait_for_vblank added in commit 9d0498a2bf7455159b317f19531a3e5db2ecc9c4 periodic stalls were being triggered (which were detected by i915_hangcheck_elapsed). Partially revert this change for now. Signed-off-by: Sitsofe Wheeler Signed-off-by: Chris Wilson --- 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 854d8f4..3a03c62 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -2328,8 +2328,10 @@ static void i9xx_crtc_dpms(struct drm_crtc *crtc, int mode) I915_READ(dspbase_reg); } - /* Wait for vblank for the disable to take effect */ - intel_wait_for_vblank_off(dev, pipe); + if (!IS_I9XX(dev)) { + /* Wait for vblank for the disable to take effect */ + intel_wait_for_vblank_off(dev, pipe); + } /* Don't disable pipe A or pipe A PLLs if needed */ if (pipeconf_reg == PIPEACONF && -- cgit v1.1 From b8ed2a4f12870bf2ea9c07ff83ccd9d8b6abc2c6 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Sun, 5 Sep 2010 00:43:42 +0100 Subject: drm/i915/tv: Preserve reserved DAC bits during mode-setting Signed-off-by: Chris Wilson --- drivers/gpu/drm/i915/i915_reg.h | 1 + drivers/gpu/drm/i915/intel_tv.c | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index d094e91..e240de9 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -1481,6 +1481,7 @@ # define TV_TEST_MODE_MASK (7 << 0) #define TV_DAC 0x68004 +# define TV_DAC_SAVE 0x00ffff00 /** * Reports that DAC state change logic has reported change (RO). * diff --git a/drivers/gpu/drm/i915/intel_tv.c b/drivers/gpu/drm/i915/intel_tv.c index c671f60..fc5c6f2 100644 --- a/drivers/gpu/drm/i915/intel_tv.c +++ b/drivers/gpu/drm/i915/intel_tv.c @@ -1196,7 +1196,7 @@ intel_tv_mode_set(struct drm_encoder *encoder, struct drm_display_mode *mode, I915_WRITE(TV_V_LUMA_0 + (i<<2), tv_mode->filter_table[j++]); for (i = 0; i < 43; i++) I915_WRITE(TV_V_CHROMA_0 + (i<<2), tv_mode->filter_table[j++]); - I915_WRITE(TV_DAC, 0); + I915_WRITE(TV_DAC, I915_READ(TV_DAC) & TV_DAC_SAVE); I915_WRITE(TV_CTL, tv_ctl); } -- cgit v1.1 From 974b93315b2213b74a42a87e8a9d4fc8c0dbe90c Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Sun, 5 Sep 2010 00:44:20 +0100 Subject: drm/i915/tv: Poll for DAC state change Instead of sleeping for an arbitrary length of time (the documentation fails to specify how long to wait for) wait until the load detection has changed state (or at most the 20ms as before). Signed-off-by: Chris Wilson --- drivers/gpu/drm/i915/intel_tv.c | 73 +++++++++++++++++++---------------------- 1 file changed, 33 insertions(+), 40 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_tv.c b/drivers/gpu/drm/i915/intel_tv.c index fc5c6f2..b7f4dca 100644 --- a/drivers/gpu/drm/i915/intel_tv.c +++ b/drivers/gpu/drm/i915/intel_tv.c @@ -1234,9 +1234,7 @@ intel_tv_detect_type (struct intel_tv *intel_tv) unsigned long irqflags; u32 tv_ctl, save_tv_ctl; u32 tv_dac, save_tv_dac; - int type = DRM_MODE_CONNECTOR_Unknown; - - tv_dac = I915_READ(TV_DAC); + int type; /* Disable TV interrupts around load detect or we'll recurse */ spin_lock_irqsave(&dev_priv->user_irq_lock, irqflags); @@ -1244,19 +1242,14 @@ intel_tv_detect_type (struct intel_tv *intel_tv) PIPE_HOTPLUG_TV_INTERRUPT_ENABLE); spin_unlock_irqrestore(&dev_priv->user_irq_lock, irqflags); - /* - * Detect TV by polling) - */ - save_tv_dac = tv_dac; - tv_ctl = I915_READ(TV_CTL); - save_tv_ctl = tv_ctl; - tv_ctl &= ~TV_ENC_ENABLE; - tv_ctl &= ~TV_TEST_MODE_MASK; + save_tv_dac = tv_dac = I915_READ(TV_DAC); + save_tv_ctl = tv_ctl = I915_READ(TV_CTL); + + /* Poll for TV detection */ + tv_ctl &= ~(TV_ENC_ENABLE | TV_TEST_MODE_MASK); tv_ctl |= TV_TEST_MODE_MONITOR_DETECT; - tv_dac &= ~TVDAC_SENSE_MASK; - tv_dac &= ~DAC_A_MASK; - tv_dac &= ~DAC_B_MASK; - tv_dac &= ~DAC_C_MASK; + + tv_dac &= ~(TVDAC_SENSE_MASK | DAC_A_MASK | DAC_B_MASK | DAC_C_MASK); tv_dac |= (TVDAC_STATE_CHG_EN | TVDAC_A_SENSE_CTL | TVDAC_B_SENSE_CTL | @@ -1265,37 +1258,37 @@ intel_tv_detect_type (struct intel_tv *intel_tv) DAC_A_0_7_V | DAC_B_0_7_V | DAC_C_0_7_V); + I915_WRITE(TV_CTL, tv_ctl); I915_WRITE(TV_DAC, tv_dac); POSTING_READ(TV_DAC); - msleep(20); - - tv_dac = I915_READ(TV_DAC); - I915_WRITE(TV_DAC, save_tv_dac); - I915_WRITE(TV_CTL, save_tv_ctl); - POSTING_READ(TV_CTL); - msleep(20); - /* - * A B C - * 0 1 1 Composite - * 1 0 X svideo - * 0 0 0 Component - */ - if ((tv_dac & TVDAC_SENSE_MASK) == (TVDAC_B_SENSE | TVDAC_C_SENSE)) { - DRM_DEBUG_KMS("Detected Composite TV connection\n"); - type = DRM_MODE_CONNECTOR_Composite; - } else if ((tv_dac & (TVDAC_A_SENSE|TVDAC_B_SENSE)) == TVDAC_A_SENSE) { - DRM_DEBUG_KMS("Detected S-Video TV connection\n"); - type = DRM_MODE_CONNECTOR_SVIDEO; - } else if ((tv_dac & TVDAC_SENSE_MASK) == 0) { - DRM_DEBUG_KMS("Detected Component TV connection\n"); - type = DRM_MODE_CONNECTOR_Component; - } else { - DRM_DEBUG_KMS("No TV connection detected\n"); - type = -1; + type = -1; + if (wait_for((tv_dac = I915_READ(TV_DAC)) & TVDAC_STATE_CHG, 20) == 0) { + /* + * A B C + * 0 1 1 Composite + * 1 0 X svideo + * 0 0 0 Component + */ + if ((tv_dac & TVDAC_SENSE_MASK) == (TVDAC_B_SENSE | TVDAC_C_SENSE)) { + DRM_DEBUG_KMS("Detected Composite TV connection\n"); + type = DRM_MODE_CONNECTOR_Composite; + } else if ((tv_dac & (TVDAC_A_SENSE|TVDAC_B_SENSE)) == TVDAC_A_SENSE) { + DRM_DEBUG_KMS("Detected S-Video TV connection\n"); + type = DRM_MODE_CONNECTOR_SVIDEO; + } else if ((tv_dac & TVDAC_SENSE_MASK) == 0) { + DRM_DEBUG_KMS("Detected Component TV connection\n"); + type = DRM_MODE_CONNECTOR_Component; + } else { + DRM_DEBUG_KMS("Unrecognised TV connection: %x\n", + tv_dac); + } } + I915_WRITE(TV_DAC, save_tv_dac & ~TVDAC_STATE_CHG_EN); + I915_WRITE(TV_CTL, save_tv_ctl); + /* Restore interrupt config */ spin_lock_irqsave(&dev_priv->user_irq_lock, irqflags); i915_enable_pipestat(dev_priv, 0, PIPE_HOTPLUG_INTERRUPT_ENABLE | -- cgit v1.1 From 763a4a019105dccdcd44883f1712571ae8ea8f1f Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Sun, 5 Sep 2010 00:52:34 +0100 Subject: drm/i915/tv: Mark the format names as constant and so avoid the memleak Signed-off-by: Chris Wilson --- drivers/gpu/drm/i915/intel_tv.c | 36 +++++++++++++++++------------------- 1 file changed, 17 insertions(+), 19 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_tv.c b/drivers/gpu/drm/i915/intel_tv.c index b7f4dca..4a65342 100644 --- a/drivers/gpu/drm/i915/intel_tv.c +++ b/drivers/gpu/drm/i915/intel_tv.c @@ -48,7 +48,7 @@ struct intel_tv { struct intel_encoder base; int type; - char *tv_format; + const char *tv_format; int margin[4]; u32 save_TV_H_CTL_1; u32 save_TV_H_CTL_2; @@ -350,7 +350,7 @@ static const struct video_levels component_levels = { struct tv_mode { - char *name; + const char *name; int clock; int refresh; /* in millihertz (for precision) */ u32 oversample; @@ -922,7 +922,7 @@ intel_tv_dpms(struct drm_encoder *encoder, int mode) } static const struct tv_mode * -intel_tv_mode_lookup (char *tv_format) +intel_tv_mode_lookup(const char *tv_format) { int i; @@ -936,13 +936,14 @@ intel_tv_mode_lookup (char *tv_format) } static const struct tv_mode * -intel_tv_mode_find (struct intel_tv *intel_tv) +intel_tv_mode_find(struct intel_tv *intel_tv) { return intel_tv_mode_lookup(intel_tv->tv_format); } static enum drm_mode_status -intel_tv_mode_valid(struct drm_connector *connector, struct drm_display_mode *mode) +intel_tv_mode_valid(struct drm_connector *connector, + struct drm_display_mode *mode) { struct drm_encoder *encoder = intel_attached_encoder(connector); struct intel_tv *intel_tv = enc_to_intel_tv(encoder); @@ -952,6 +953,7 @@ intel_tv_mode_valid(struct drm_connector *connector, struct drm_display_mode *mo if (tv_mode && abs(tv_mode->refresh - drm_mode_vrefresh(mode) * 1000) < 1000) return MODE_OK; + return MODE_CLOCK_RANGE; } @@ -1369,11 +1371,10 @@ intel_tv_detect(struct drm_connector *connector) return connector_status_connected; } -static struct input_res { - char *name; +static const struct input_res { + const char *name; int w, h; -} input_res_table[] = -{ +} input_res_table[] = { {"640x480", 640, 480}, {"800x600", 800, 600}, {"1024x768", 1024, 768}, @@ -1424,7 +1425,7 @@ intel_tv_get_modes(struct drm_connector *connector) for (j = 0; j < ARRAY_SIZE(input_res_table); j++) { - struct input_res *input = &input_res_table[j]; + const struct input_res *input = &input_res_table[j]; unsigned int hactive_s = input->w; unsigned int vactive_s = input->h; @@ -1601,7 +1602,7 @@ intel_tv_init(struct drm_device *dev) struct intel_encoder *intel_encoder; struct intel_connector *intel_connector; u32 tv_dac_on, tv_dac_off, save_tv_dac; - char **tv_format_names; + char *tv_format_names[ARRAY_SIZE(tv_modes)]; int i, initial_mode = 0; if ((I915_READ(TV_CTL) & TV_FUSE_STATE_MASK) == TV_FUSE_STATE_DISABLED) @@ -1672,7 +1673,7 @@ intel_tv_init(struct drm_device *dev) intel_tv->margin[TV_MARGIN_RIGHT] = 46; intel_tv->margin[TV_MARGIN_BOTTOM] = 37; - intel_tv->tv_format = kstrdup(tv_modes[initial_mode].name, GFP_KERNEL); + intel_tv->tv_format = tv_modes[initial_mode].name; drm_encoder_helper_add(&intel_encoder->enc, &intel_tv_helper_funcs); drm_connector_helper_add(connector, &intel_tv_connector_helper_funcs); @@ -1680,13 +1681,11 @@ intel_tv_init(struct drm_device *dev) connector->doublescan_allowed = false; /* Create TV properties then attach current values */ - tv_format_names = kmalloc(sizeof(char *) * ARRAY_SIZE(tv_modes), - GFP_KERNEL); - if (!tv_format_names) - goto out; for (i = 0; i < ARRAY_SIZE(tv_modes); i++) - tv_format_names[i] = tv_modes[i].name; - drm_mode_create_tv_properties(dev, ARRAY_SIZE(tv_modes), tv_format_names); + tv_format_names[i] = (char *)tv_modes[i].name; + drm_mode_create_tv_properties(dev, + ARRAY_SIZE(tv_modes), + tv_format_names); drm_connector_attach_property(connector, dev->mode_config.tv_mode_property, initial_mode); @@ -1702,6 +1701,5 @@ intel_tv_init(struct drm_device *dev) drm_connector_attach_property(connector, dev->mode_config.tv_bottom_margin_property, intel_tv->margin[TV_MARGIN_BOTTOM]); -out: drm_sysfs_connector_add(connector); } -- cgit v1.1 From 57cd6508da65adabcb14be6ba3b9370d750b647d Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Sun, 8 Aug 2010 12:34:44 +0100 Subject: drm/i915: Sanity check user framebuffer parameters on creation Signed-off-by: Chris Wilson --- drivers/gpu/drm/i915/intel_display.c | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 3a03c62..adce193 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -5371,8 +5371,25 @@ int intel_framebuffer_init(struct drm_device *dev, struct drm_mode_fb_cmd *mode_cmd, struct drm_gem_object *obj) { + struct drm_i915_gem_object *obj_priv = to_intel_bo(obj); int ret; + if (obj_priv->tiling_mode == I915_TILING_Y) + return -EINVAL; + + if (mode_cmd->pitch & 63) + return -EINVAL; + + switch (mode_cmd->bpp) { + case 8: + case 16: + case 24: + case 32: + break; + default: + return -EINVAL; + } + ret = drm_framebuffer_init(dev, &intel_fb->base, &intel_fb_funcs); if (ret) { DRM_ERROR("framebuffer init failed %d\n", ret); -- cgit v1.1 From 6c9547ff354d867318d78094aa8e9cf5218851e2 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Wed, 25 Aug 2010 10:05:17 +0100 Subject: drm/i915/sdvo: Preserve pixel-multiplier Store the pixel-multiplier on the adjusted mode and avoid modifying the requested mode. Signed-off-by: Chris Wilson --- drivers/gpu/drm/i915/intel_display.c | 25 +++++---- drivers/gpu/drm/i915/intel_drv.h | 18 +++++++ drivers/gpu/drm/i915/intel_sdvo.c | 99 +++++++++++++++--------------------- 3 files changed, 75 insertions(+), 67 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index adce193..120a9c0 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -3519,7 +3519,6 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc, int trans_dpll_sel = (pipe == 0) ? 0 : 1; int lvds_reg = LVDS; u32 temp; - int sdvo_pixel_multiply; int target_clock; drm_vblank_pre_modeset(dev, pipe); @@ -3770,12 +3769,14 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc, else dpll |= DPLLB_MODE_DAC_SERIAL; if (is_sdvo) { + int pixel_multiplier = intel_mode_get_pixel_multiplier(adjusted_mode); + if (pixel_multiplier > 1) { + if (IS_I945G(dev) || IS_I945GM(dev) || IS_G33(dev)) + dpll |= (pixel_multiplier - 1) << SDVO_MULTIPLIER_SHIFT_HIRES; + else if (HAS_PCH_SPLIT(dev)) + dpll |= (pixel_multiplier - 1) << PLL_REF_SDVO_HDMI_MULTIPLIER_SHIFT; + } dpll |= DPLL_DVO_HIGH_SPEED; - sdvo_pixel_multiply = adjusted_mode->clock / mode->clock; - if (IS_I945G(dev) || IS_I945GM(dev) || IS_G33(dev)) - dpll |= (sdvo_pixel_multiply - 1) << SDVO_MULTIPLIER_SHIFT_HIRES; - else if (HAS_PCH_SPLIT(dev)) - dpll |= (sdvo_pixel_multiply - 1) << PLL_REF_SDVO_HDMI_MULTIPLIER_SHIFT; } if (is_dp) dpll |= DPLL_DVO_HIGH_SPEED; @@ -3982,9 +3983,15 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc, if (IS_I965G(dev) && !HAS_PCH_SPLIT(dev)) { if (is_sdvo) { - sdvo_pixel_multiply = adjusted_mode->clock / mode->clock; - I915_WRITE(dpll_md_reg, (0 << DPLL_MD_UDI_DIVIDER_SHIFT) | - ((sdvo_pixel_multiply - 1) << DPLL_MD_UDI_MULTIPLIER_SHIFT)); + int pixel_multiplier = intel_mode_get_pixel_multiplier(adjusted_mode); + if (pixel_multiplier > 1) + pixel_multiplier = (pixel_multiplier - 1) << DPLL_MD_UDI_MULTIPLIER_SHIFT; + else + pixel_multiplier = 0; + + I915_WRITE(dpll_md_reg, + (0 << DPLL_MD_UDI_DIVIDER_SHIFT) | + pixel_multiplier); } else I915_WRITE(dpll_md_reg, 0); } else { diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index 1ca3c9e..64a7c87 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -99,6 +99,24 @@ #define INTEL_DVO_CHIP_TMDS 2 #define INTEL_DVO_CHIP_TVOUT 4 +/* drm_display_mode->private_flags */ +#define INTEL_MODE_PIXEL_MULTIPLIER_SHIFT (0x0) +#define INTEL_MODE_PIXEL_MULTIPLIER_MASK (0xf << INTEL_MODE_PIXEL_MULTIPLIER_SHIFT) + +static inline void +intel_mode_set_pixel_multiplier(struct drm_display_mode *mode, + int multiplier) +{ + mode->clock *= multiplier; + mode->private_flags |= multiplier; +} + +static inline int +intel_mode_get_pixel_multiplier(const struct drm_display_mode *mode) +{ + return (mode->private_flags & INTEL_MODE_PIXEL_MULTIPLIER_MASK) >> INTEL_MODE_PIXEL_MULTIPLIER_SHIFT; +} + struct intel_i2c_chan { struct drm_device *drm_dev; /* for getting at dev. private (mmio etc.) */ u32 reg; /* GPIO reg */ diff --git a/drivers/gpu/drm/i915/intel_sdvo.c b/drivers/gpu/drm/i915/intel_sdvo.c index e3b7a7e..1c1aeea 100644 --- a/drivers/gpu/drm/i915/intel_sdvo.c +++ b/drivers/gpu/drm/i915/intel_sdvo.c @@ -106,16 +106,12 @@ struct intel_sdvo { bool is_hdmi; /** - * This is set if we detect output of sdvo device as LVDS. + * This is set if we detect output of sdvo device as LVDS and + * have a valid fixed mode to use with the panel. */ bool is_lvds; /** - * This is sdvo flags for input timing. - */ - uint8_t sdvo_flags; - - /** * This is sdvo fixed pannel mode pointer */ struct drm_display_mode *sdvo_lvds_fixed_mode; @@ -132,6 +128,8 @@ struct intel_sdvo { /* Mac mini hack -- use the same DDC as the analog connector */ struct i2c_adapter *analog_ddc_bus; + /* Input timings for adjusted_mode */ + struct intel_sdvo_dtd input_dtd; }; struct intel_sdvo_connector { @@ -1022,8 +1020,6 @@ intel_sdvo_set_input_timings_for_mode(struct intel_sdvo *intel_sdvo, struct drm_display_mode *mode, struct drm_display_mode *adjusted_mode) { - struct intel_sdvo_dtd input_dtd; - /* Reset the input timing to the screen. Assume always input 0. */ if (!intel_sdvo_set_target_input(intel_sdvo)) return false; @@ -1035,14 +1031,12 @@ intel_sdvo_set_input_timings_for_mode(struct intel_sdvo *intel_sdvo, return false; if (!intel_sdvo_get_preferred_input_timing(intel_sdvo, - &input_dtd)) + &intel_sdvo->input_dtd)) return false; - intel_sdvo_get_mode_from_dtd(adjusted_mode, &input_dtd); - intel_sdvo->sdvo_flags = input_dtd.part2.sdvo_flags; + intel_sdvo_get_mode_from_dtd(adjusted_mode, &intel_sdvo->input_dtd); drm_mode_set_crtcinfo(adjusted_mode, 0); - mode->clock = adjusted_mode->clock; return true; } @@ -1051,6 +1045,7 @@ static bool intel_sdvo_mode_fixup(struct drm_encoder *encoder, struct drm_display_mode *adjusted_mode) { struct intel_sdvo *intel_sdvo = enc_to_intel_sdvo(encoder); + int multiplier; /* We need to construct preferred input timings based on our * output timings. To do that, we have to set the output @@ -1065,10 +1060,8 @@ static bool intel_sdvo_mode_fixup(struct drm_encoder *encoder, mode, adjusted_mode); } else if (intel_sdvo->is_lvds) { - drm_mode_set_crtcinfo(intel_sdvo->sdvo_lvds_fixed_mode, 0); - if (!intel_sdvo_set_output_timings_from_mode(intel_sdvo, - intel_sdvo->sdvo_lvds_fixed_mode)) + intel_sdvo->sdvo_lvds_fixed_mode)) return false; (void) intel_sdvo_set_input_timings_for_mode(intel_sdvo, @@ -1077,9 +1070,10 @@ static bool intel_sdvo_mode_fixup(struct drm_encoder *encoder, } /* Make the CRTC code factor in the SDVO pixel multiplier. The - * SDVO device will be told of the multiplier during mode_set. + * SDVO device will factor out the multiplier during mode_set. */ - adjusted_mode->clock *= intel_sdvo_get_pixel_multiplier(mode); + multiplier = intel_sdvo_get_pixel_multiplier(adjusted_mode); + intel_mode_set_pixel_multiplier(adjusted_mode, multiplier); return true; } @@ -1093,10 +1087,11 @@ static void intel_sdvo_mode_set(struct drm_encoder *encoder, struct drm_crtc *crtc = encoder->crtc; struct intel_crtc *intel_crtc = to_intel_crtc(crtc); struct intel_sdvo *intel_sdvo = enc_to_intel_sdvo(encoder); - u32 sdvox = 0; - int sdvo_pixel_multiply, rate; + u32 sdvox; struct intel_sdvo_in_out_map in_out; struct intel_sdvo_dtd input_dtd; + int pixel_multiplier = intel_mode_get_pixel_multiplier(adjusted_mode); + int rate; if (!mode) return; @@ -1114,28 +1109,23 @@ static void intel_sdvo_mode_set(struct drm_encoder *encoder, SDVO_CMD_SET_IN_OUT_MAP, &in_out, sizeof(in_out)); - if (intel_sdvo->is_hdmi) { - if (!intel_sdvo_set_avi_infoframe(intel_sdvo, mode)) - return; - - sdvox |= SDVO_AUDIO_ENABLE; - } + /* Set the output timings to the screen */ + if (!intel_sdvo_set_target_output(intel_sdvo, + intel_sdvo->attached_output)) + return; /* We have tried to get input timing in mode_fixup, and filled into - adjusted_mode */ - intel_sdvo_get_dtd_from_mode(&input_dtd, adjusted_mode); - if (intel_sdvo->is_tv || intel_sdvo->is_lvds) - input_dtd.part2.sdvo_flags = intel_sdvo->sdvo_flags; - - /* If it's a TV, we already set the output timing in mode_fixup. - * Otherwise, the output timing is equal to the input timing. + * adjusted_mode. */ - if (!intel_sdvo->is_tv && !intel_sdvo->is_lvds) { + if (intel_sdvo->is_tv || intel_sdvo->is_lvds) { + input_dtd = intel_sdvo->input_dtd; + } else { /* Set the output timing to the screen */ if (!intel_sdvo_set_target_output(intel_sdvo, intel_sdvo->attached_output)) return; + intel_sdvo_get_dtd_from_mode(&input_dtd, adjusted_mode); (void) intel_sdvo_set_output_timing(intel_sdvo, &input_dtd); } @@ -1143,31 +1133,18 @@ static void intel_sdvo_mode_set(struct drm_encoder *encoder, if (!intel_sdvo_set_target_input(intel_sdvo)) return; - if (intel_sdvo->is_tv) { - if (!intel_sdvo_set_tv_format(intel_sdvo)) - return; - } + if (intel_sdvo->is_hdmi && + !intel_sdvo_set_avi_infoframe(intel_sdvo, mode)) + return; - /* We would like to use intel_sdvo_create_preferred_input_timing() to - * provide the device with a timing it can support, if it supports that - * feature. However, presumably we would need to adjust the CRTC to - * output the preferred timing, and we don't support that currently. - */ -#if 0 - success = intel_sdvo_create_preferred_input_timing(encoder, clock, - width, height); - if (success) { - struct intel_sdvo_dtd *input_dtd; + if (intel_sdvo->is_tv && + !intel_sdvo_set_tv_format(intel_sdvo)) + return; - intel_sdvo_get_preferred_input_timing(encoder, &input_dtd); - intel_sdvo_set_input_timing(encoder, &input_dtd); - } -#else (void) intel_sdvo_set_input_timing(intel_sdvo, &input_dtd); -#endif - sdvo_pixel_multiply = intel_sdvo_get_pixel_multiplier(mode); - switch (sdvo_pixel_multiply) { + switch (pixel_multiplier) { + default: case 1: rate = SDVO_CLOCK_RATE_MULT_1X; break; case 2: rate = SDVO_CLOCK_RATE_MULT_2X; break; case 4: rate = SDVO_CLOCK_RATE_MULT_4X; break; @@ -1177,13 +1154,13 @@ static void intel_sdvo_mode_set(struct drm_encoder *encoder, /* Set the SDVO control regs. */ if (IS_I965G(dev)) { - sdvox |= SDVO_BORDER_ENABLE; + sdvox = SDVO_BORDER_ENABLE; if (adjusted_mode->flags & DRM_MODE_FLAG_PVSYNC) sdvox |= SDVO_VSYNC_ACTIVE_HIGH; if (adjusted_mode->flags & DRM_MODE_FLAG_PHSYNC) sdvox |= SDVO_HSYNC_ACTIVE_HIGH; } else { - sdvox |= I915_READ(intel_sdvo->sdvo_reg); + sdvox = I915_READ(intel_sdvo->sdvo_reg); switch (intel_sdvo->sdvo_reg) { case SDVOB: sdvox &= SDVOB_PRESERVE_MASK; @@ -1196,16 +1173,18 @@ static void intel_sdvo_mode_set(struct drm_encoder *encoder, } if (intel_crtc->pipe == 1) sdvox |= SDVO_PIPE_B_SELECT; + if (intel_sdvo->is_hdmi) + sdvox |= SDVO_AUDIO_ENABLE; if (IS_I965G(dev)) { /* done in crtc_mode_set as the dpll_md reg must be written early */ } else if (IS_I945G(dev) || IS_I945GM(dev) || IS_G33(dev)) { /* done in crtc_mode_set as it lives inside the dpll register */ } else { - sdvox |= (sdvo_pixel_multiply - 1) << SDVO_PORT_MULTIPLY_SHIFT; + sdvox |= (pixel_multiplier - 1) << SDVO_PORT_MULTIPLY_SHIFT; } - if (intel_sdvo->sdvo_flags & SDVO_NEED_TO_STALL) + if (input_dtd.part2.sdvo_flags & SDVO_NEED_TO_STALL) sdvox |= SDVO_STALL_SELECT; intel_sdvo_write_sdvox(intel_sdvo, sdvox); } @@ -1692,6 +1671,10 @@ end: if (newmode->type & DRM_MODE_TYPE_PREFERRED) { intel_sdvo->sdvo_lvds_fixed_mode = drm_mode_duplicate(connector->dev, newmode); + + drm_mode_set_crtcinfo(intel_sdvo->sdvo_lvds_fixed_mode, + 0); + intel_sdvo->is_lvds = true; break; } -- cgit v1.1 From be282fd48e7492812402a22d73a348c44bf95b63 Mon Sep 17 00:00:00 2001 From: Jesse Barnes Date: Fri, 13 Aug 2010 15:50:28 -0700 Subject: drm/i915: add MMIO debug output Useful for capturing register read/write traces to send to the hw guys. Signed-off-by: Jesse Barnes Signed-off-by: Chris Wilson --- drivers/gpu/drm/i915/i915_drv.h | 30 ++++++++++++++++++++++++++++-- 1 file changed, 28 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index f6940f1..2692410 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -264,6 +264,9 @@ typedef struct drm_i915_private { int front_offset; int current_page; int page_flipping; +#define I915_DEBUG_READ (1<<0) +#define I915_DEBUG_WRITE (1<<1) + unsigned long debug_flags; wait_queue_head_t irq_queue; atomic_t irq_received; @@ -1100,8 +1103,26 @@ extern void intel_overlay_print_error_state(struct seq_file *m, struct intel_ove LOCK_TEST_WITH_RETURN(dev, file_priv); \ } while (0) -#define I915_READ(reg) readl(dev_priv->regs + (reg)) -#define I915_WRITE(reg, val) writel(val, dev_priv->regs + (reg)) +static inline u32 i915_read(struct drm_i915_private *dev_priv, u32 reg) +{ + u32 val; + + val = readl(dev_priv->regs + reg); + if (dev_priv->debug_flags & I915_DEBUG_READ) + printk(KERN_ERR "read 0x%08x from 0x%08x\n", val, reg); + return val; +} + +static inline void i915_write(struct drm_i915_private *dev_priv, u32 reg, + u32 val) +{ + writel(val, dev_priv->regs + reg); + if (dev_priv->debug_flags & I915_DEBUG_WRITE) + printk(KERN_ERR "wrote 0x%08x to 0x%08x\n", val, reg); +} + +#define I915_READ(reg) i915_read(dev_priv, (reg)) +#define I915_WRITE(reg, val) i915_write(dev_priv, (reg), (val)) #define I915_READ16(reg) readw(dev_priv->regs + (reg)) #define I915_WRITE16(reg, val) writel(val, dev_priv->regs + (reg)) #define I915_READ8(reg) readb(dev_priv->regs + (reg)) @@ -1111,6 +1132,11 @@ extern void intel_overlay_print_error_state(struct seq_file *m, struct intel_ove #define POSTING_READ(reg) (void)I915_READ(reg) #define POSTING_READ16(reg) (void)I915_READ16(reg) +#define I915_DEBUG_ENABLE_IO() (dev_priv->debug_flags |= I915_DEBUG_READ | \ + I915_DEBUG_WRITE) +#define I915_DEBUG_DISABLE_IO() (dev_priv->debug_flags &= ~(I915_DEBUG_READ | \ + I915_DEBUG_WRITE)) + #define I915_VERBOSE 0 #define BEGIN_LP_RING(n) do { \ -- cgit v1.1 From e35a41de3926ec81e3ed2ed31d1f30cecb3513f9 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Thu, 11 Feb 2010 22:13:59 +0100 Subject: drm/i915: allow lazy emitting of requests Sometimes (like when flushing in preparation of batchbuffer execution) we know that we'll emit a request but haven't yet done so. Allow this case by simply taking the next seqno by default. Ensure that a request is eventually emitted before waiting for an request by issuing it in i915_wait_request iff this is not yet done. Also replace one open-coded version of i915_gem_object_wait_rendering, to prevent future code-diversion. Chris Wilson asked me to explain and clarify what this patch does and why. Here it goes: Old way of moving objects onto the active list and associating them with a reques: 1. i915_add_request + store the returned seqno somewhere 2. i915_gem_object_move_to_active (with the stored seqno as parameter) For the current users, this is all fine. But I'd like to associate objects (and fence regs) with the batchbuffer request deep down in the execbuf call-chain. I thought about three ways of implementing this. a) Don't care, just emit request when we need a new seqno. When heavily pipelining fence reg changes, this would have caused tons of superflous request (and corresponding irqs). b) Thread all changed fences, objects, whatever through the execbuf-maze, so that when we emit a request, we can store the new seqno at all the right places. c) Kill that seqno-threading-around business by simply storing the next seqno, i.e. allow 2. to be done before 1. in the above sequence. I've decided to implement c) (in this patch). The following patches are just fall-out that resulted from this small conceptual change. * We can handle the flushing list processing where we actually emit a flush (i915_gem_flush and i915_retire_commands) instead of in i915_add_request. The code makes IMHO more sense this way (and i915_add_request looses the flush_domains parameter, obviously). * We can avoid emitting unnecessary requests. IMHO there's no point in emitting more than one request per batchbuffer (with or without an corresponding irq). * By enforcing 2. before 1. ordering in the above sequence the seqno argument of i915_gem_object_move_to_active is redundant and can be dropped. v2: Now i915_wait_request issues request if it is not yet emitted. Also introduce i915_gem_next_request_seqno(dev) just in case we ever need to do some prep work before using a new seqno. Signed-off-by: Daniel Vetter [ickle: Keep i915_gem_object_set_to_display_plane() uninterruptible.] Signed-off-by: Chris Wilson --- drivers/gpu/drm/i915/i915_gem.c | 55 +++++++++++++++++++++++++---------------- 1 file changed, 34 insertions(+), 21 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index 26eb6e3..1fed3e6 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -46,7 +46,8 @@ static int i915_gem_object_set_cpu_read_domain_range(struct drm_gem_object *obj, uint64_t offset, uint64_t size); static void i915_gem_object_set_to_full_cpu_read_domain(struct drm_gem_object *obj); -static int i915_gem_object_wait_rendering(struct drm_gem_object *obj); +static int i915_gem_object_wait_rendering(struct drm_gem_object *obj, + bool interruptible); static int i915_gem_object_bind_to_gtt(struct drm_gem_object *obj, unsigned alignment); static void i915_gem_clear_fence_reg(struct drm_gem_object *obj); @@ -1468,6 +1469,14 @@ i915_gem_object_put_pages(struct drm_gem_object *obj) obj_priv->pages = NULL; } +static uint32_t +i915_gem_next_request_seqno(struct drm_device *dev) +{ + drm_i915_private_t *dev_priv = dev->dev_private; + + return dev_priv->next_seqno; +} + static void i915_gem_object_move_to_active(struct drm_gem_object *obj, uint32_t seqno, struct intel_ring_buffer *ring) @@ -1483,6 +1492,11 @@ i915_gem_object_move_to_active(struct drm_gem_object *obj, uint32_t seqno, drm_gem_object_reference(obj); obj_priv->active = 1; } + + /* Take the seqno of the next request if none is given */ + if (seqno == 0) + seqno = i915_gem_next_request_seqno(dev); + /* Move from whatever list we were on to the tail of execution. */ spin_lock(&dev_priv->mm.active_list_lock); list_move_tail(&obj_priv->list, &ring->active_list); @@ -1828,6 +1842,12 @@ i915_do_wait_request(struct drm_device *dev, uint32_t seqno, BUG_ON(seqno == 0); + if (seqno == dev_priv->next_seqno) { + seqno = i915_add_request(dev, NULL, 0, ring); + if (seqno == 0) + return -ENOMEM; + } + if (atomic_read(&dev_priv->mm.wedged)) return -EIO; @@ -1915,7 +1935,8 @@ i915_gem_flush(struct drm_device *dev, * safe to unbind from the GTT or access from the CPU. */ static int -i915_gem_object_wait_rendering(struct drm_gem_object *obj) +i915_gem_object_wait_rendering(struct drm_gem_object *obj, + bool interruptible) { struct drm_device *dev = obj->dev; struct drm_i915_gem_object *obj_priv = to_intel_bo(obj); @@ -1934,8 +1955,10 @@ i915_gem_object_wait_rendering(struct drm_gem_object *obj) DRM_INFO("%s: object %p wait for seqno %08x\n", __func__, obj, obj_priv->last_rendering_seqno); #endif - ret = i915_wait_request(dev, - obj_priv->last_rendering_seqno, obj_priv->ring); + ret = i915_do_wait_request(dev, + obj_priv->last_rendering_seqno, + interruptible, + obj_priv->ring); if (ret != 0) return ret; } @@ -2438,7 +2461,7 @@ i915_gem_object_put_fence_reg(struct drm_gem_object *obj) if (ret != 0) return ret; - ret = i915_gem_object_wait_rendering(obj); + ret = i915_gem_object_wait_rendering(obj, true); if (ret != 0) return ret; } @@ -2694,7 +2717,7 @@ i915_gem_object_set_to_gtt_domain(struct drm_gem_object *obj, int write) return ret; /* Wait on any GPU rendering and flushing to occur. */ - ret = i915_gem_object_wait_rendering(obj); + ret = i915_gem_object_wait_rendering(obj, true); if (ret != 0) return ret; @@ -2733,7 +2756,6 @@ i915_gem_object_set_to_gtt_domain(struct drm_gem_object *obj, int write) int i915_gem_object_set_to_display_plane(struct drm_gem_object *obj) { - struct drm_device *dev = obj->dev; struct drm_i915_gem_object *obj_priv = to_intel_bo(obj); uint32_t old_write_domain, old_read_domains; int ret; @@ -2747,18 +2769,9 @@ i915_gem_object_set_to_display_plane(struct drm_gem_object *obj) return ret; /* Wait on any GPU rendering and flushing to occur. */ - if (obj_priv->active) { -#if WATCH_BUF - DRM_INFO("%s: object %p wait for seqno %08x\n", - __func__, obj, obj_priv->last_rendering_seqno); -#endif - ret = i915_do_wait_request(dev, - obj_priv->last_rendering_seqno, - 0, - obj_priv->ring); - if (ret != 0) - return ret; - } + ret = i915_gem_object_wait_rendering(obj, false); + if (ret != 0) + return ret; i915_gem_object_flush_cpu_write_domain(obj); @@ -2797,7 +2810,7 @@ i915_gem_object_set_to_cpu_domain(struct drm_gem_object *obj, int write) return ret; /* Wait on any GPU rendering and flushing to occur. */ - ret = i915_gem_object_wait_rendering(obj); + ret = i915_gem_object_wait_rendering(obj, true); if (ret != 0) return ret; @@ -3098,7 +3111,7 @@ i915_gem_object_set_cpu_read_domain_range(struct drm_gem_object *obj, return ret; /* Wait on any GPU rendering and flushing to occur. */ - ret = i915_gem_object_wait_rendering(obj); + ret = i915_gem_object_wait_rendering(obj, true); if (ret != 0) return ret; i915_gem_object_flush_gtt_write_domain(obj); -- cgit v1.1 From 8bff917c93e365a8a145f9b1be99c81257038151 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Thu, 11 Feb 2010 22:19:40 +0100 Subject: drm/i915: move flushing list processing to i915_gem_flush Now that we can move objects to the active list without already having emitted a request, move the flushing list handling into i915_gem_flush. This makes more sense and allows to drop a few i915_add_request calls that are not strictly necessary. Signed-off-by: Daniel Vetter Signed-off-by: Chris Wilson --- drivers/gpu/drm/i915/i915_gem.c | 31 +++++++++++++++++++++---------- 1 file changed, 21 insertions(+), 10 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index 1fed3e6..eea8232 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -1637,7 +1637,7 @@ i915_add_request(struct drm_device *dev, struct drm_file *file_priv, } /* Associate any objects on the flushing list matching the write - * domain we're flushing with our flush. + * domain we're flushing with our request. */ if (flush_domains != 0) i915_gem_process_flushing_list(dev, flush_domains, seqno, ring); @@ -1887,8 +1887,9 @@ i915_do_wait_request(struct drm_device *dev, uint32_t seqno, ret = -EIO; if (ret && ret != -ERESTARTSYS) - DRM_ERROR("%s returns %d (awaiting %d at %d)\n", - __func__, ret, seqno, ring->get_gem_seqno(dev, ring)); + DRM_ERROR("%s returns %d (awaiting %d at %d, next %d)\n", + __func__, ret, seqno, ring->get_gem_seqno(dev, ring), + dev_priv->next_seqno); /* Directly dispatch request retiring. While we have the work queue * to handle this, the waiter on a request often wants an associated @@ -1918,8 +1919,10 @@ i915_gem_flush(struct drm_device *dev, uint32_t flush_domains) { drm_i915_private_t *dev_priv = dev->dev_private; + if (flush_domains & I915_GEM_DOMAIN_CPU) drm_agp_chipset_flush(dev); + dev_priv->render_ring.flush(dev, &dev_priv->render_ring, invalidate_domains, flush_domains); @@ -1928,6 +1931,17 @@ i915_gem_flush(struct drm_device *dev, dev_priv->bsd_ring.flush(dev, &dev_priv->bsd_ring, invalidate_domains, flush_domains); + + /* Associate any objects on the flushing list matching the write + * domain we're flushing with the next request. + */ + if (flush_domains != 0) { + i915_gem_process_flushing_list(dev, flush_domains, 0, + &dev_priv->render_ring); + if (HAS_BSD(dev)) + i915_gem_process_flushing_list(dev, flush_domains, 0, + &dev_priv->bsd_ring); + } } /** @@ -2061,14 +2075,14 @@ i915_gpu_idle(struct drm_device *dev) /* Flush everything onto the inactive list. */ i915_gem_flush(dev, I915_GEM_GPU_DOMAINS, I915_GEM_GPU_DOMAINS); - seqno1 = i915_add_request(dev, NULL, I915_GEM_GPU_DOMAINS, + seqno1 = i915_add_request(dev, NULL, 0, &dev_priv->render_ring); if (seqno1 == 0) return -ENOMEM; ret = i915_wait_request(dev, seqno1, &dev_priv->render_ring); if (HAS_BSD(dev)) { - seqno2 = i915_add_request(dev, NULL, I915_GEM_GPU_DOMAINS, + seqno2 = i915_add_request(dev, NULL, 0, &dev_priv->bsd_ring); if (seqno2 == 0) return -ENOMEM; @@ -2078,7 +2092,6 @@ i915_gpu_idle(struct drm_device *dev) return ret; } - return ret; } @@ -3771,12 +3784,10 @@ i915_gem_do_execbuffer(struct drm_device *dev, void *data, dev->invalidate_domains, dev->flush_domains); if (dev_priv->flush_rings & FLUSH_RENDER_RING) - (void)i915_add_request(dev, file_priv, - dev->flush_domains, + (void)i915_add_request(dev, file_priv, 0, &dev_priv->render_ring); if (dev_priv->flush_rings & FLUSH_BSD_RING) - (void)i915_add_request(dev, file_priv, - dev->flush_domains, + (void)i915_add_request(dev, file_priv, 0, &dev_priv->bsd_ring); } -- cgit v1.1 From a6910434e1b5f2a9fe7cab39b01bae9a7a7bbe70 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Tue, 2 Feb 2010 17:08:37 +0100 Subject: drm/i915: only one interrupt per batchbuffer is not enough! Previously I thought that one interrupt per batchbuffer should be enough. Now tedious benchmarking showed this to be wrong. Therefore track whether any commands have been isssued with a future seqno (like pipelined fencing changes or flushes). If this is the case emit a request before issueing the batchbuffer. Signed-off-by: Daniel Vetter Signed-off-by: Chris Wilson --- drivers/gpu/drm/i915/i915_drv.h | 3 --- drivers/gpu/drm/i915/i915_gem.c | 33 ++++++++++++++++----------------- drivers/gpu/drm/i915/intel_ringbuffer.h | 5 +++++ 3 files changed, 21 insertions(+), 20 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 2692410..fb8d681 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -293,9 +293,6 @@ typedef struct drm_i915_private { unsigned int sr01, adpa, ppcr, dvob, dvoc, lvds; int vblank_pipe; int num_pipe; - u32 flush_rings; -#define FLUSH_RENDER_RING 0x1 -#define FLUSH_BSD_RING 0x2 /* For hangcheck timer */ #define DRM_I915_HANGCHECK_PERIOD 75 /* in jiffies */ diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index eea8232..b52f47a 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -1470,10 +1470,13 @@ i915_gem_object_put_pages(struct drm_gem_object *obj) } static uint32_t -i915_gem_next_request_seqno(struct drm_device *dev) +i915_gem_next_request_seqno(struct drm_device *dev, + struct intel_ring_buffer *ring) { drm_i915_private_t *dev_priv = dev->dev_private; + ring->outstanding_lazy_request = true; + return dev_priv->next_seqno; } @@ -1495,7 +1498,7 @@ i915_gem_object_move_to_active(struct drm_gem_object *obj, uint32_t seqno, /* Take the seqno of the next request if none is given */ if (seqno == 0) - seqno = i915_gem_next_request_seqno(dev); + seqno = i915_gem_next_request_seqno(dev, ring); /* Move from whatever list we were on to the tail of execution. */ spin_lock(&dev_priv->mm.active_list_lock); @@ -2979,7 +2982,6 @@ static void i915_gem_object_set_to_gpu_domain(struct drm_gem_object *obj) { struct drm_device *dev = obj->dev; - drm_i915_private_t *dev_priv = dev->dev_private; struct drm_i915_gem_object *obj_priv = to_intel_bo(obj); uint32_t invalidate_domains = 0; uint32_t flush_domains = 0; @@ -3042,13 +3044,6 @@ i915_gem_object_set_to_gpu_domain(struct drm_gem_object *obj) obj->pending_write_domain = obj->write_domain; obj->read_domains = obj->pending_read_domains; - if (flush_domains & I915_GEM_GPU_DOMAINS) { - if (obj_priv->ring == &dev_priv->render_ring) - dev_priv->flush_rings |= FLUSH_RENDER_RING; - else if (obj_priv->ring == &dev_priv->bsd_ring) - dev_priv->flush_rings |= FLUSH_BSD_RING; - } - dev->invalidate_domains |= invalidate_domains; dev->flush_domains |= flush_domains; #if WATCH_BUF @@ -3762,7 +3757,6 @@ i915_gem_do_execbuffer(struct drm_device *dev, void *data, */ dev->invalidate_domains = 0; dev->flush_domains = 0; - dev_priv->flush_rings = 0; for (i = 0; i < args->buffer_count; i++) { struct drm_gem_object *obj = object_list[i]; @@ -3783,12 +3777,17 @@ i915_gem_do_execbuffer(struct drm_device *dev, void *data, i915_gem_flush(dev, dev->invalidate_domains, dev->flush_domains); - if (dev_priv->flush_rings & FLUSH_RENDER_RING) - (void)i915_add_request(dev, file_priv, 0, - &dev_priv->render_ring); - if (dev_priv->flush_rings & FLUSH_BSD_RING) - (void)i915_add_request(dev, file_priv, 0, - &dev_priv->bsd_ring); + } + + if (dev_priv->render_ring.outstanding_lazy_request) { + (void)i915_add_request(dev, file_priv, 0, + &dev_priv->render_ring); + dev_priv->render_ring.outstanding_lazy_request = false; + } + if (dev_priv->bsd_ring.outstanding_lazy_request) { + (void)i915_add_request(dev, file_priv, 0, + &dev_priv->bsd_ring); + dev_priv->bsd_ring.outstanding_lazy_request = false; } for (i = 0; i < args->buffer_count; i++) { diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.h b/drivers/gpu/drm/i915/intel_ringbuffer.h index 525e7d3..d3e5f40 100644 --- a/drivers/gpu/drm/i915/intel_ringbuffer.h +++ b/drivers/gpu/drm/i915/intel_ringbuffer.h @@ -83,6 +83,11 @@ struct intel_ring_buffer { */ struct list_head request_list; + /** + * Do we have some not yet emitted requests outstanding? + */ + bool outstanding_lazy_request; + wait_queue_head_t irq_queue; drm_local_map_t map; }; -- cgit v1.1 From 8a1a49f954734040dbc7b87e3b1221a050045e43 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Thu, 11 Feb 2010 22:29:04 +0100 Subject: drm/i915: move flushing list processing to i915_retire_commands ... instead of threading flush_domains through the execbuf code to i915_add_request. With this change 2 small cleanups are possible (likewise the majority of the patch): - The flush_domains parameter of i915_add_request is always 0. Drop it and the corresponding logic. - Ditto for the seqno param of i915_gem_process_flushing_list. Signed-off-by: Daniel Vetter Signed-off-by: Chris Wilson --- drivers/gpu/drm/i915/i915_drv.h | 9 +++-- drivers/gpu/drm/i915/i915_gem.c | 64 ++++++++++++--------------------- drivers/gpu/drm/i915/intel_overlay.c | 17 ++++----- drivers/gpu/drm/i915/intel_ringbuffer.c | 4 +++ 4 files changed, 41 insertions(+), 53 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index fb8d681..f983130 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -991,12 +991,15 @@ int i915_gpu_idle(struct drm_device *dev); int i915_gem_idle(struct drm_device *dev); uint32_t i915_add_request(struct drm_device *dev, struct drm_file *file_priv, - uint32_t flush_domains, struct intel_ring_buffer *ring); int i915_do_wait_request(struct drm_device *dev, - uint32_t seqno, int interruptible, - struct intel_ring_buffer *ring); + uint32_t seqno, + bool interruptible, + struct intel_ring_buffer *ring); int i915_gem_fault(struct vm_area_struct *vma, struct vm_fault *vmf); +void i915_gem_process_flushing_list(struct drm_device *dev, + uint32_t flush_domains, + struct intel_ring_buffer *ring); int i915_gem_object_set_to_gtt_domain(struct drm_gem_object *obj, int write); int i915_gem_object_set_to_display_plane(struct drm_gem_object *obj); diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index b52f47a..46394f7 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -1570,9 +1570,9 @@ i915_gem_object_move_to_inactive(struct drm_gem_object *obj) i915_verify_inactive(dev, __FILE__, __LINE__); } -static void +void i915_gem_process_flushing_list(struct drm_device *dev, - uint32_t flush_domains, uint32_t seqno, + uint32_t flush_domains, struct intel_ring_buffer *ring) { drm_i915_private_t *dev_priv = dev->dev_private; @@ -1590,7 +1590,7 @@ i915_gem_process_flushing_list(struct drm_device *dev, obj->write_domain = 0; list_del_init(&obj_priv->gpu_write_list); - i915_gem_object_move_to_active(obj, seqno, ring); + i915_gem_object_move_to_active(obj, 0, ring); /* update the fence lru list */ if (obj_priv->fence_reg != I915_FENCE_REG_NONE) { @@ -1608,8 +1608,9 @@ i915_gem_process_flushing_list(struct drm_device *dev, } uint32_t -i915_add_request(struct drm_device *dev, struct drm_file *file_priv, - uint32_t flush_domains, struct intel_ring_buffer *ring) +i915_add_request(struct drm_device *dev, + struct drm_file *file_priv, + struct intel_ring_buffer *ring) { drm_i915_private_t *dev_priv = dev->dev_private; struct drm_i915_file_private *i915_file_priv = NULL; @@ -1624,7 +1625,7 @@ i915_add_request(struct drm_device *dev, struct drm_file *file_priv, if (request == NULL) return 0; - seqno = ring->add_request(dev, ring, file_priv, flush_domains); + seqno = ring->add_request(dev, ring, file_priv, 0); request->seqno = seqno; request->ring = ring; @@ -1639,12 +1640,6 @@ i915_add_request(struct drm_device *dev, struct drm_file *file_priv, INIT_LIST_HEAD(&request->client_list); } - /* Associate any objects on the flushing list matching the write - * domain we're flushing with our request. - */ - if (flush_domains != 0) - i915_gem_process_flushing_list(dev, flush_domains, seqno, ring); - if (!dev_priv->mm.suspended) { mod_timer(&dev_priv->hangcheck_timer, jiffies + DRM_I915_HANGCHECK_PERIOD); if (was_empty) @@ -1659,7 +1654,7 @@ i915_add_request(struct drm_device *dev, struct drm_file *file_priv, * Ensures that all commands in the ring are finished * before signalling the CPU */ -static uint32_t +static void i915_retire_commands(struct drm_device *dev, struct intel_ring_buffer *ring) { uint32_t flush_domains = 0; @@ -1670,7 +1665,6 @@ i915_retire_commands(struct drm_device *dev, struct intel_ring_buffer *ring) ring->flush(dev, ring, I915_GEM_DOMAIN_COMMAND, flush_domains); - return flush_domains; } /** @@ -1837,7 +1831,7 @@ i915_gem_retire_work_handler(struct work_struct *work) int i915_do_wait_request(struct drm_device *dev, uint32_t seqno, - int interruptible, struct intel_ring_buffer *ring) + bool interruptible, struct intel_ring_buffer *ring) { drm_i915_private_t *dev_priv = dev->dev_private; u32 ier; @@ -1846,7 +1840,7 @@ i915_do_wait_request(struct drm_device *dev, uint32_t seqno, BUG_ON(seqno == 0); if (seqno == dev_priv->next_seqno) { - seqno = i915_add_request(dev, NULL, 0, ring); + seqno = i915_add_request(dev, NULL, ring); if (seqno == 0) return -ENOMEM; } @@ -1934,17 +1928,6 @@ i915_gem_flush(struct drm_device *dev, dev_priv->bsd_ring.flush(dev, &dev_priv->bsd_ring, invalidate_domains, flush_domains); - - /* Associate any objects on the flushing list matching the write - * domain we're flushing with the next request. - */ - if (flush_domains != 0) { - i915_gem_process_flushing_list(dev, flush_domains, 0, - &dev_priv->render_ring); - if (HAS_BSD(dev)) - i915_gem_process_flushing_list(dev, flush_domains, 0, - &dev_priv->bsd_ring); - } } /** @@ -2078,24 +2061,23 @@ i915_gpu_idle(struct drm_device *dev) /* Flush everything onto the inactive list. */ i915_gem_flush(dev, I915_GEM_GPU_DOMAINS, I915_GEM_GPU_DOMAINS); - seqno1 = i915_add_request(dev, NULL, 0, - &dev_priv->render_ring); + seqno1 = i915_add_request(dev, NULL, &dev_priv->render_ring); if (seqno1 == 0) return -ENOMEM; ret = i915_wait_request(dev, seqno1, &dev_priv->render_ring); + if (ret) + return ret; if (HAS_BSD(dev)) { - seqno2 = i915_add_request(dev, NULL, 0, - &dev_priv->bsd_ring); + seqno2 = i915_add_request(dev, NULL, &dev_priv->bsd_ring); if (seqno2 == 0) return -ENOMEM; - ret = i915_wait_request(dev, seqno2, &dev_priv->bsd_ring); if (ret) return ret; } - return ret; + return 0; } int @@ -2641,7 +2623,7 @@ i915_gem_object_flush_gpu_write_domain(struct drm_gem_object *obj) /* Queue the GPU write cache flushing we need. */ old_write_domain = obj->write_domain; i915_gem_flush(dev, 0, obj->write_domain); - if (i915_add_request(dev, NULL, obj->write_domain, obj_priv->ring) == 0) + if (i915_add_request(dev, NULL, obj_priv->ring) == 0) return -ENOMEM; trace_i915_gem_object_change_domain(obj, @@ -3564,7 +3546,7 @@ i915_gem_do_execbuffer(struct drm_device *dev, void *data, struct drm_i915_gem_relocation_entry *relocs = NULL; int ret = 0, ret2, i, pinned = 0; uint64_t exec_offset; - uint32_t seqno, flush_domains, reloc_index; + uint32_t seqno, reloc_index; int pin_tries, flips; struct intel_ring_buffer *ring = NULL; @@ -3780,13 +3762,11 @@ i915_gem_do_execbuffer(struct drm_device *dev, void *data, } if (dev_priv->render_ring.outstanding_lazy_request) { - (void)i915_add_request(dev, file_priv, 0, - &dev_priv->render_ring); + (void)i915_add_request(dev, file_priv, &dev_priv->render_ring); dev_priv->render_ring.outstanding_lazy_request = false; } if (dev_priv->bsd_ring.outstanding_lazy_request) { - (void)i915_add_request(dev, file_priv, 0, - &dev_priv->bsd_ring); + (void)i915_add_request(dev, file_priv, &dev_priv->bsd_ring); dev_priv->bsd_ring.outstanding_lazy_request = false; } @@ -3835,7 +3815,7 @@ i915_gem_do_execbuffer(struct drm_device *dev, void *data, * Ensure that the commands in the batch buffer are * finished before the interrupt fires */ - flush_domains = i915_retire_commands(dev, ring); + i915_retire_commands(dev, ring); i915_verify_inactive(dev, __FILE__, __LINE__); @@ -3846,7 +3826,7 @@ i915_gem_do_execbuffer(struct drm_device *dev, void *data, * *some* interrupts representing completion of buffers that we can * wait on when trying to clear up gtt space). */ - seqno = i915_add_request(dev, file_priv, flush_domains, ring); + seqno = i915_add_request(dev, file_priv, ring); BUG_ON(seqno == 0); for (i = 0; i < args->buffer_count; i++) { struct drm_gem_object *obj = object_list[i]; @@ -4244,7 +4224,7 @@ i915_gem_busy_ioctl(struct drm_device *dev, void *data, */ if (obj->write_domain) { i915_gem_flush(dev, 0, obj->write_domain); - (void)i915_add_request(dev, file_priv, obj->write_domain, obj_priv->ring); + (void)i915_add_request(dev, file_priv, obj_priv->ring); } /* Update the active list for the hardware's current position. diff --git a/drivers/gpu/drm/i915/intel_overlay.c b/drivers/gpu/drm/i915/intel_overlay.c index 1d306a4..a203b5c 100644 --- a/drivers/gpu/drm/i915/intel_overlay.c +++ b/drivers/gpu/drm/i915/intel_overlay.c @@ -230,7 +230,7 @@ static int intel_overlay_on(struct intel_overlay *overlay) ADVANCE_LP_RING(); overlay->last_flip_req = - i915_add_request(dev, NULL, 0, &dev_priv->render_ring); + i915_add_request(dev, NULL, &dev_priv->render_ring); if (overlay->last_flip_req == 0) return -ENOMEM; @@ -269,7 +269,7 @@ static void intel_overlay_continue(struct intel_overlay *overlay, ADVANCE_LP_RING(); overlay->last_flip_req = - i915_add_request(dev, NULL, 0, &dev_priv->render_ring); + i915_add_request(dev, NULL, &dev_priv->render_ring); } static int intel_overlay_wait_flip(struct intel_overlay *overlay) @@ -301,7 +301,7 @@ static int intel_overlay_wait_flip(struct intel_overlay *overlay) ADVANCE_LP_RING(); overlay->last_flip_req = - i915_add_request(dev, NULL, 0, &dev_priv->render_ring); + i915_add_request(dev, NULL, &dev_priv->render_ring); if (overlay->last_flip_req == 0) return -ENOMEM; @@ -342,7 +342,7 @@ static int intel_overlay_off(struct intel_overlay *overlay) ADVANCE_LP_RING(); overlay->last_flip_req = - i915_add_request(dev, NULL, 0, &dev_priv->render_ring); + i915_add_request(dev, NULL, &dev_priv->render_ring); if (overlay->last_flip_req == 0) return -ENOMEM; @@ -362,7 +362,7 @@ static int intel_overlay_off(struct intel_overlay *overlay) ADVANCE_LP_RING(); overlay->last_flip_req = - i915_add_request(dev, NULL, 0, &dev_priv->render_ring); + i915_add_request(dev, NULL, &dev_priv->render_ring); if (overlay->last_flip_req == 0) return -ENOMEM; @@ -409,7 +409,7 @@ int intel_overlay_recover_from_interrupt(struct intel_overlay *overlay, if (overlay->last_flip_req == 0) { overlay->last_flip_req = - i915_add_request(dev, NULL, 0, &dev_priv->render_ring); + i915_add_request(dev, NULL, &dev_priv->render_ring); if (overlay->last_flip_req == 0) return -ENOMEM; } @@ -439,8 +439,9 @@ int intel_overlay_recover_from_interrupt(struct intel_overlay *overlay, OUT_RING(MI_NOOP); ADVANCE_LP_RING(); - overlay->last_flip_req = i915_add_request(dev, NULL, - 0, &dev_priv->render_ring); + overlay->last_flip_req = + i915_add_request(dev, NULL, + &dev_priv->render_ring); if (overlay->last_flip_req == 0) return -ENOMEM; diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.c b/drivers/gpu/drm/i915/intel_ringbuffer.c index cb3508f..1ae2b25 100644 --- a/drivers/gpu/drm/i915/intel_ringbuffer.c +++ b/drivers/gpu/drm/i915/intel_ringbuffer.c @@ -116,6 +116,8 @@ render_ring_flush(struct drm_device *dev, intel_ring_emit(dev, ring, MI_NOOP); intel_ring_advance(dev, ring); } + + i915_gem_process_flushing_list(dev, flush_domains, ring); } static unsigned int render_ring_get_head(struct drm_device *dev, @@ -384,6 +386,8 @@ bsd_ring_flush(struct drm_device *dev, intel_ring_emit(dev, ring, MI_FLUSH); intel_ring_emit(dev, ring, MI_NOOP); intel_ring_advance(dev, ring); + + i915_gem_process_flushing_list(dev, flush_domains, ring); } static inline unsigned int bsd_ring_get_head(struct drm_device *dev, -- cgit v1.1 From 86394c669a485cb773ddef9f2b66bebdb23241d0 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Tue, 2 Feb 2010 22:54:18 +0100 Subject: drm/i915: kill a no longer necessary BUG_ON i915_gem_object_move_to_active can handle zero seqno for us now. And not emitting a request is not fatal here - we'll try to emit a new one if we have to wait for some rendering to complete. In case this assumption ever gets accidentally broken, there's already a BUG_ON to catch it in i915_do_wait_request. So just silently ignore ENOMEM here instead of screwing up the whole drm. Signed-off-by: Daniel Vetter Signed-off-by: Chris Wilson --- drivers/gpu/drm/i915/i915_gem.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index 46394f7..a54b813 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -3827,7 +3827,6 @@ i915_gem_do_execbuffer(struct drm_device *dev, void *data, * wait on when trying to clear up gtt space). */ seqno = i915_add_request(dev, file_priv, ring); - BUG_ON(seqno == 0); for (i = 0; i < args->buffer_count; i++) { struct drm_gem_object *obj = object_list[i]; obj_priv = to_intel_bo(obj); -- cgit v1.1 From 617dbe2787568316eed976f533f93c31fdbc75b9 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Thu, 11 Feb 2010 22:16:02 +0100 Subject: drm/i915: drop seqno argument from i915_gem_object_move_to_active By moving one i915_add_request we can solely depend on the new auto-seqno-numbering behaviour. Signed-off-by: Daniel Vetter Signed-off-by: Chris Wilson --- drivers/gpu/drm/i915/i915_gem.c | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index a54b813..4c043cb 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -1481,12 +1481,14 @@ i915_gem_next_request_seqno(struct drm_device *dev, } static void -i915_gem_object_move_to_active(struct drm_gem_object *obj, uint32_t seqno, +i915_gem_object_move_to_active(struct drm_gem_object *obj, struct intel_ring_buffer *ring) { struct drm_device *dev = obj->dev; drm_i915_private_t *dev_priv = dev->dev_private; struct drm_i915_gem_object *obj_priv = to_intel_bo(obj); + uint32_t seqno = i915_gem_next_request_seqno(dev, ring); + BUG_ON(ring == NULL); obj_priv->ring = ring; @@ -1496,10 +1498,6 @@ i915_gem_object_move_to_active(struct drm_gem_object *obj, uint32_t seqno, obj_priv->active = 1; } - /* Take the seqno of the next request if none is given */ - if (seqno == 0) - seqno = i915_gem_next_request_seqno(dev, ring); - /* Move from whatever list we were on to the tail of execution. */ spin_lock(&dev_priv->mm.active_list_lock); list_move_tail(&obj_priv->list, &ring->active_list); @@ -1590,7 +1588,7 @@ i915_gem_process_flushing_list(struct drm_device *dev, obj->write_domain = 0; list_del_init(&obj_priv->gpu_write_list); - i915_gem_object_move_to_active(obj, 0, ring); + i915_gem_object_move_to_active(obj, ring); /* update the fence lru list */ if (obj_priv->fence_reg != I915_FENCE_REG_NONE) { @@ -3819,6 +3817,16 @@ i915_gem_do_execbuffer(struct drm_device *dev, void *data, i915_verify_inactive(dev, __FILE__, __LINE__); + for (i = 0; i < args->buffer_count; i++) { + struct drm_gem_object *obj = object_list[i]; + obj_priv = to_intel_bo(obj); + + i915_gem_object_move_to_active(obj, ring); +#if WATCH_LRU + DRM_INFO("%s: move to exec list %p\n", __func__, obj); +#endif + } + /* * Get a seqno representing the execution of the current buffer, * which we can wait on. We would like to mitigate these interrupts, @@ -3827,15 +3835,7 @@ i915_gem_do_execbuffer(struct drm_device *dev, void *data, * wait on when trying to clear up gtt space). */ seqno = i915_add_request(dev, file_priv, ring); - for (i = 0; i < args->buffer_count; i++) { - struct drm_gem_object *obj = object_list[i]; - obj_priv = to_intel_bo(obj); - i915_gem_object_move_to_active(obj, seqno, ring); -#if WATCH_LRU - DRM_INFO("%s: move to exec list %p\n", __func__, obj); -#endif - } #if WATCH_LRU i915_dump_lru(dev, __func__); #endif -- cgit v1.1 From ba3d8d749b01548b918519a49024341d8dc9e71c Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Thu, 11 Feb 2010 22:37:04 +0100 Subject: drm/i915: move the wait_rendering call into flush_gpu_write_domain One caller (for the pageflip support) wants a purely pipelined flush. Distinguish this case by a new parameter. This will also be useful later on for pipelined fencing. v2: Simplify the code by depending upon the implicit request emitting of i915_wait_request. Signed-off-by: Daniel Vetter [ickle: And drop the non-interruptible support in the process.] Signed-off-by: Chris Wilson --- drivers/gpu/drm/i915/i915_gem.c | 88 ++++++++++++++++------------------------- 1 file changed, 33 insertions(+), 55 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index 4c043cb..9f13aaa 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -37,7 +37,9 @@ #include static uint32_t i915_gem_get_gtt_alignment(struct drm_gem_object *obj); -static int i915_gem_object_flush_gpu_write_domain(struct drm_gem_object *obj); + +static int i915_gem_object_flush_gpu_write_domain(struct drm_gem_object *obj, + bool pipelined); static void i915_gem_object_flush_gtt_write_domain(struct drm_gem_object *obj); static void i915_gem_object_flush_cpu_write_domain(struct drm_gem_object *obj); static int i915_gem_object_set_to_cpu_domain(struct drm_gem_object *obj, @@ -46,8 +48,7 @@ static int i915_gem_object_set_cpu_read_domain_range(struct drm_gem_object *obj, uint64_t offset, uint64_t size); static void i915_gem_object_set_to_full_cpu_read_domain(struct drm_gem_object *obj); -static int i915_gem_object_wait_rendering(struct drm_gem_object *obj, - bool interruptible); +static int i915_gem_object_wait_rendering(struct drm_gem_object *obj); static int i915_gem_object_bind_to_gtt(struct drm_gem_object *obj, unsigned alignment); static void i915_gem_clear_fence_reg(struct drm_gem_object *obj); @@ -1933,8 +1934,7 @@ i915_gem_flush(struct drm_device *dev, * safe to unbind from the GTT or access from the CPU. */ static int -i915_gem_object_wait_rendering(struct drm_gem_object *obj, - bool interruptible) +i915_gem_object_wait_rendering(struct drm_gem_object *obj) { struct drm_device *dev = obj->dev; struct drm_i915_gem_object *obj_priv = to_intel_bo(obj); @@ -1953,10 +1953,9 @@ i915_gem_object_wait_rendering(struct drm_gem_object *obj, DRM_INFO("%s: object %p wait for seqno %08x\n", __func__, obj, obj_priv->last_rendering_seqno); #endif - ret = i915_do_wait_request(dev, - obj_priv->last_rendering_seqno, - interruptible, - obj_priv->ring); + ret = i915_wait_request(dev, + obj_priv->last_rendering_seqno, + obj_priv->ring); if (ret != 0) return ret; } @@ -2453,11 +2452,7 @@ i915_gem_object_put_fence_reg(struct drm_gem_object *obj) if (!IS_I965G(dev)) { int ret; - ret = i915_gem_object_flush_gpu_write_domain(obj); - if (ret != 0) - return ret; - - ret = i915_gem_object_wait_rendering(obj, true); + ret = i915_gem_object_flush_gpu_write_domain(obj, false); if (ret != 0) return ret; } @@ -2609,11 +2604,11 @@ i915_gem_clflush_object(struct drm_gem_object *obj) /** Flushes any GPU write domain for the object if it's dirty. */ static int -i915_gem_object_flush_gpu_write_domain(struct drm_gem_object *obj) +i915_gem_object_flush_gpu_write_domain(struct drm_gem_object *obj, + bool pipelined) { struct drm_device *dev = obj->dev; uint32_t old_write_domain; - struct drm_i915_gem_object *obj_priv = to_intel_bo(obj); if ((obj->write_domain & I915_GEM_GPU_DOMAINS) == 0) return 0; @@ -2621,13 +2616,15 @@ i915_gem_object_flush_gpu_write_domain(struct drm_gem_object *obj) /* Queue the GPU write cache flushing we need. */ old_write_domain = obj->write_domain; i915_gem_flush(dev, 0, obj->write_domain); - if (i915_add_request(dev, NULL, obj_priv->ring) == 0) - return -ENOMEM; trace_i915_gem_object_change_domain(obj, obj->read_domains, old_write_domain); - return 0; + + if (pipelined) + return 0; + + return i915_gem_object_wait_rendering(obj); } /** Flushes the GTT write domain for the object if it's dirty. */ @@ -2684,7 +2681,7 @@ i915_gem_object_flush_write_domain(struct drm_gem_object *obj) i915_gem_object_flush_cpu_write_domain(obj); break; default: - ret = i915_gem_object_flush_gpu_write_domain(obj); + ret = i915_gem_object_flush_gpu_write_domain(obj, true); break; } @@ -2708,12 +2705,7 @@ i915_gem_object_set_to_gtt_domain(struct drm_gem_object *obj, int write) if (obj_priv->gtt_space == NULL) return -EINVAL; - ret = i915_gem_object_flush_gpu_write_domain(obj); - if (ret != 0) - return ret; - - /* Wait on any GPU rendering and flushing to occur. */ - ret = i915_gem_object_wait_rendering(obj, true); + ret = i915_gem_object_flush_gpu_write_domain(obj, false); if (ret != 0) return ret; @@ -2723,8 +2715,13 @@ i915_gem_object_set_to_gtt_domain(struct drm_gem_object *obj, int write) /* If we're writing through the GTT domain, then CPU and GPU caches * will need to be invalidated at next use. */ - if (write) + if (write) { + ret = i915_gem_object_wait_rendering(obj); + if (ret) + return ret; + obj->read_domains &= I915_GEM_DOMAIN_GTT; + } i915_gem_object_flush_cpu_write_domain(obj); @@ -2753,38 +2750,25 @@ int i915_gem_object_set_to_display_plane(struct drm_gem_object *obj) { struct drm_i915_gem_object *obj_priv = to_intel_bo(obj); - uint32_t old_write_domain, old_read_domains; + uint32_t old_read_domains; int ret; /* Not valid to be called on unbound objects. */ if (obj_priv->gtt_space == NULL) return -EINVAL; - ret = i915_gem_object_flush_gpu_write_domain(obj); - if (ret) - return ret; - - /* Wait on any GPU rendering and flushing to occur. */ - ret = i915_gem_object_wait_rendering(obj, false); + ret = i915_gem_object_flush_gpu_write_domain(obj, true); if (ret != 0) return ret; i915_gem_object_flush_cpu_write_domain(obj); - old_write_domain = obj->write_domain; old_read_domains = obj->read_domains; - - /* It should now be out of any other write domains, and we can update - * the domain values for our changes. - */ - BUG_ON((obj->write_domain & ~I915_GEM_DOMAIN_GTT) != 0); obj->read_domains = I915_GEM_DOMAIN_GTT; - obj->write_domain = I915_GEM_DOMAIN_GTT; - obj_priv->dirty = 1; trace_i915_gem_object_change_domain(obj, old_read_domains, - old_write_domain); + obj->write_domain); return 0; } @@ -2801,12 +2785,7 @@ i915_gem_object_set_to_cpu_domain(struct drm_gem_object *obj, int write) uint32_t old_write_domain, old_read_domains; int ret; - ret = i915_gem_object_flush_gpu_write_domain(obj); - if (ret) - return ret; - - /* Wait on any GPU rendering and flushing to occur. */ - ret = i915_gem_object_wait_rendering(obj, true); + ret = i915_gem_object_flush_gpu_write_domain(obj, false); if (ret != 0) return ret; @@ -2836,6 +2815,10 @@ i915_gem_object_set_to_cpu_domain(struct drm_gem_object *obj, int write) * need to be invalidated at next use. */ if (write) { + ret = i915_gem_object_wait_rendering(obj); + if (ret) + return ret; + obj->read_domains &= I915_GEM_DOMAIN_CPU; obj->write_domain = I915_GEM_DOMAIN_CPU; } @@ -3094,12 +3077,7 @@ i915_gem_object_set_cpu_read_domain_range(struct drm_gem_object *obj, if (offset == 0 && size == obj->size) return i915_gem_object_set_to_cpu_domain(obj, 0); - ret = i915_gem_object_flush_gpu_write_domain(obj); - if (ret) - return ret; - - /* Wait on any GPU rendering and flushing to occur. */ - ret = i915_gem_object_wait_rendering(obj, true); + ret = i915_gem_object_flush_gpu_write_domain(obj, false); if (ret != 0) return ret; i915_gem_object_flush_gtt_write_domain(obj); -- cgit v1.1 From 4fc6ee764620eb3a9364e736d03605d4b233ea61 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Thu, 11 Feb 2010 22:53:20 +0100 Subject: drm/i915: drop i915_add_request right in front of i915_wait_request ... take advantage of the new implicit request issuing of i915_wait_request. Signed-off-by: Daniel Vetter Signed-off-by: Chris Wilson --- drivers/gpu/drm/i915/i915_gem.c | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index 9f13aaa..ce66f90 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -2043,7 +2043,6 @@ i915_gpu_idle(struct drm_device *dev) { drm_i915_private_t *dev_priv = dev->dev_private; bool lists_empty; - uint32_t seqno1, seqno2; int ret; spin_lock(&dev_priv->mm.active_list_lock); @@ -2058,18 +2057,17 @@ i915_gpu_idle(struct drm_device *dev) /* Flush everything onto the inactive list. */ i915_gem_flush(dev, I915_GEM_GPU_DOMAINS, I915_GEM_GPU_DOMAINS); - seqno1 = i915_add_request(dev, NULL, &dev_priv->render_ring); - if (seqno1 == 0) - return -ENOMEM; - ret = i915_wait_request(dev, seqno1, &dev_priv->render_ring); + + ret = i915_wait_request(dev, + i915_gem_next_request_seqno(dev, &dev_priv->render_ring), + &dev_priv->render_ring); if (ret) return ret; if (HAS_BSD(dev)) { - seqno2 = i915_add_request(dev, NULL, &dev_priv->bsd_ring); - if (seqno2 == 0) - return -ENOMEM; - ret = i915_wait_request(dev, seqno2, &dev_priv->bsd_ring); + ret = i915_wait_request(dev, + i915_gem_next_request_seqno(dev, &dev_priv->bsd_ring), + &dev_priv->bsd_ring); if (ret) return ret; } -- cgit v1.1 From 722506f04dae7c88193dab2fc836ff15070190f0 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Thu, 12 Aug 2010 09:28:50 +0100 Subject: drm/i915/overlay: Whitespace Signed-off-by: Chris Wilson Reviewed-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_drv.h | 2 +- drivers/gpu/drm/i915/intel_overlay.c | 458 ++++++++++++++++++----------------- 2 files changed, 236 insertions(+), 224 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index 64a7c87..72f72f5 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -291,7 +291,7 @@ extern void intel_setup_overlay(struct drm_device *dev); extern void intel_cleanup_overlay(struct drm_device *dev); extern int intel_overlay_switch_off(struct intel_overlay *overlay); extern int intel_overlay_recover_from_interrupt(struct intel_overlay *overlay, - int interruptible); + bool interruptible); extern int intel_overlay_put_image(struct drm_device *dev, void *data, struct drm_file *file_priv); extern int intel_overlay_attrs(struct drm_device *dev, void *data, diff --git a/drivers/gpu/drm/i915/intel_overlay.c b/drivers/gpu/drm/i915/intel_overlay.c index a203b5c..5ed1783 100644 --- a/drivers/gpu/drm/i915/intel_overlay.c +++ b/drivers/gpu/drm/i915/intel_overlay.c @@ -176,7 +176,6 @@ struct overlay_registers { #define OVERLAY_NONPHYSICAL(dev) (IS_G33(dev) || IS_I965G(dev)) #define OVERLAY_EXISTS(dev) (!IS_G4X(dev) && !IS_IRONLAKE(dev) && !IS_GEN6(dev)) - static struct overlay_registers *intel_overlay_map_regs_atomic(struct intel_overlay *overlay) { drm_i915_private_t *dev_priv = overlay->dev->dev_private; @@ -235,7 +234,8 @@ static int intel_overlay_on(struct intel_overlay *overlay) return -ENOMEM; ret = i915_do_wait_request(dev, - overlay->last_flip_req, 1, &dev_priv->render_ring); + overlay->last_flip_req, true, + &dev_priv->render_ring); if (ret != 0) return ret; @@ -246,7 +246,7 @@ static int intel_overlay_on(struct intel_overlay *overlay) /* overlay needs to be enabled in OCMD reg */ static void intel_overlay_continue(struct intel_overlay *overlay, - bool load_polyphase_filter) + bool load_polyphase_filter) { struct drm_device *dev = overlay->dev; drm_i915_private_t *dev_priv = dev->dev_private; @@ -275,13 +275,14 @@ static void intel_overlay_continue(struct intel_overlay *overlay, static int intel_overlay_wait_flip(struct intel_overlay *overlay) { struct drm_device *dev = overlay->dev; - drm_i915_private_t *dev_priv = dev->dev_private; + drm_i915_private_t *dev_priv = dev->dev_private; int ret; u32 tmp; if (overlay->last_flip_req != 0) { - ret = i915_do_wait_request(dev, overlay->last_flip_req, - 1, &dev_priv->render_ring); + ret = i915_do_wait_request(dev, + overlay->last_flip_req, true, + &dev_priv->render_ring); if (ret == 0) { overlay->last_flip_req = 0; @@ -296,17 +297,18 @@ static int intel_overlay_wait_flip(struct intel_overlay *overlay) overlay->hw_wedged = RELEASE_OLD_VID; BEGIN_LP_RING(2); - OUT_RING(MI_WAIT_FOR_EVENT | MI_WAIT_FOR_OVERLAY_FLIP); - OUT_RING(MI_NOOP); - ADVANCE_LP_RING(); + OUT_RING(MI_WAIT_FOR_EVENT | MI_WAIT_FOR_OVERLAY_FLIP); + OUT_RING(MI_NOOP); + ADVANCE_LP_RING(); overlay->last_flip_req = i915_add_request(dev, NULL, &dev_priv->render_ring); if (overlay->last_flip_req == 0) return -ENOMEM; - ret = i915_do_wait_request(dev, overlay->last_flip_req, - 1, &dev_priv->render_ring); + ret = i915_do_wait_request(dev, + overlay->last_flip_req, true, + &dev_priv->render_ring); if (ret != 0) return ret; @@ -337,17 +339,18 @@ static int intel_overlay_off(struct intel_overlay *overlay) BEGIN_LP_RING(4); OUT_RING(MI_OVERLAY_FLIP | MI_OVERLAY_CONTINUE); OUT_RING(flip_addr); - OUT_RING(MI_WAIT_FOR_EVENT | MI_WAIT_FOR_OVERLAY_FLIP); - OUT_RING(MI_NOOP); - ADVANCE_LP_RING(); + OUT_RING(MI_WAIT_FOR_EVENT | MI_WAIT_FOR_OVERLAY_FLIP); + OUT_RING(MI_NOOP); + ADVANCE_LP_RING(); overlay->last_flip_req = i915_add_request(dev, NULL, &dev_priv->render_ring); if (overlay->last_flip_req == 0) return -ENOMEM; - ret = i915_do_wait_request(dev, overlay->last_flip_req, - 1, &dev_priv->render_ring); + ret = i915_do_wait_request(dev, + overlay->last_flip_req, true, + &dev_priv->render_ring); if (ret != 0) return ret; @@ -355,10 +358,10 @@ static int intel_overlay_off(struct intel_overlay *overlay) overlay->hw_wedged = SWITCH_OFF_STAGE_2; BEGIN_LP_RING(4); - OUT_RING(MI_OVERLAY_FLIP | MI_OVERLAY_OFF); + OUT_RING(MI_OVERLAY_FLIP | MI_OVERLAY_OFF); OUT_RING(flip_addr); - OUT_RING(MI_WAIT_FOR_EVENT | MI_WAIT_FOR_OVERLAY_FLIP); - OUT_RING(MI_NOOP); + OUT_RING(MI_WAIT_FOR_EVENT | MI_WAIT_FOR_OVERLAY_FLIP); + OUT_RING(MI_NOOP); ADVANCE_LP_RING(); overlay->last_flip_req = @@ -366,8 +369,9 @@ static int intel_overlay_off(struct intel_overlay *overlay) if (overlay->last_flip_req == 0) return -ENOMEM; - ret = i915_do_wait_request(dev, overlay->last_flip_req, - 1, &dev_priv->render_ring); + ret = i915_do_wait_request(dev, + overlay->last_flip_req, true, + &dev_priv->render_ring); if (ret != 0) return ret; @@ -396,7 +400,7 @@ static void intel_overlay_off_tail(struct intel_overlay *overlay) /* recover from an interruption due to a signal * We have to be careful not to repeat work forever an make forward progess. */ int intel_overlay_recover_from_interrupt(struct intel_overlay *overlay, - int interruptible) + bool interruptible) { struct drm_device *dev = overlay->dev; struct drm_gem_object *obj; @@ -415,46 +419,47 @@ int intel_overlay_recover_from_interrupt(struct intel_overlay *overlay, } ret = i915_do_wait_request(dev, overlay->last_flip_req, - interruptible, &dev_priv->render_ring); + interruptible, &dev_priv->render_ring); if (ret != 0) return ret; switch (overlay->hw_wedged) { - case RELEASE_OLD_VID: - obj = &overlay->old_vid_bo->base; - i915_gem_object_unpin(obj); - drm_gem_object_unreference(obj); - overlay->old_vid_bo = NULL; - break; - case SWITCH_OFF_STAGE_1: - flip_addr = overlay->flip_addr; - flip_addr |= OFC_UPDATE; - - overlay->hw_wedged = SWITCH_OFF_STAGE_2; - - BEGIN_LP_RING(4); - OUT_RING(MI_OVERLAY_FLIP | MI_OVERLAY_OFF); - OUT_RING(flip_addr); - OUT_RING(MI_WAIT_FOR_EVENT | MI_WAIT_FOR_OVERLAY_FLIP); - OUT_RING(MI_NOOP); - ADVANCE_LP_RING(); - - overlay->last_flip_req = - i915_add_request(dev, NULL, - &dev_priv->render_ring); - if (overlay->last_flip_req == 0) - return -ENOMEM; - - ret = i915_do_wait_request(dev, overlay->last_flip_req, - interruptible, &dev_priv->render_ring); - if (ret != 0) - return ret; + case RELEASE_OLD_VID: + obj = &overlay->old_vid_bo->base; + i915_gem_object_unpin(obj); + drm_gem_object_unreference(obj); + overlay->old_vid_bo = NULL; + break; + case SWITCH_OFF_STAGE_1: + flip_addr = overlay->flip_addr; + flip_addr |= OFC_UPDATE; - case SWITCH_OFF_STAGE_2: - intel_overlay_off_tail(overlay); - break; - default: - BUG_ON(overlay->hw_wedged != NEEDS_WAIT_FOR_FLIP); + overlay->hw_wedged = SWITCH_OFF_STAGE_2; + + BEGIN_LP_RING(4); + OUT_RING(MI_OVERLAY_FLIP | MI_OVERLAY_OFF); + OUT_RING(flip_addr); + OUT_RING(MI_WAIT_FOR_EVENT | MI_WAIT_FOR_OVERLAY_FLIP); + OUT_RING(MI_NOOP); + ADVANCE_LP_RING(); + + overlay->last_flip_req = + i915_add_request(dev, NULL, + &dev_priv->render_ring); + if (overlay->last_flip_req == 0) + return -ENOMEM; + + ret = i915_do_wait_request(dev, overlay->last_flip_req, + interruptible, + &dev_priv->render_ring); + if (ret != 0) + return ret; + + case SWITCH_OFF_STAGE_2: + intel_overlay_off_tail(overlay); + break; + default: + BUG_ON(overlay->hw_wedged != NEEDS_WAIT_FOR_FLIP); } overlay->hw_wedged = 0; @@ -507,50 +512,50 @@ struct put_image_params { static int packed_depth_bytes(u32 format) { switch (format & I915_OVERLAY_DEPTH_MASK) { - case I915_OVERLAY_YUV422: - return 4; - case I915_OVERLAY_YUV411: - /* return 6; not implemented */ - default: - return -EINVAL; + case I915_OVERLAY_YUV422: + return 4; + case I915_OVERLAY_YUV411: + /* return 6; not implemented */ + default: + return -EINVAL; } } static int packed_width_bytes(u32 format, short width) { switch (format & I915_OVERLAY_DEPTH_MASK) { - case I915_OVERLAY_YUV422: - return width << 1; - default: - return -EINVAL; + case I915_OVERLAY_YUV422: + return width << 1; + default: + return -EINVAL; } } static int uv_hsubsampling(u32 format) { switch (format & I915_OVERLAY_DEPTH_MASK) { - case I915_OVERLAY_YUV422: - case I915_OVERLAY_YUV420: - return 2; - case I915_OVERLAY_YUV411: - case I915_OVERLAY_YUV410: - return 4; - default: - return -EINVAL; + case I915_OVERLAY_YUV422: + case I915_OVERLAY_YUV420: + return 2; + case I915_OVERLAY_YUV411: + case I915_OVERLAY_YUV410: + return 4; + default: + return -EINVAL; } } static int uv_vsubsampling(u32 format) { switch (format & I915_OVERLAY_DEPTH_MASK) { - case I915_OVERLAY_YUV420: - case I915_OVERLAY_YUV410: - return 2; - case I915_OVERLAY_YUV422: - case I915_OVERLAY_YUV411: - return 1; - default: - return -EINVAL; + case I915_OVERLAY_YUV420: + case I915_OVERLAY_YUV410: + return 2; + case I915_OVERLAY_YUV422: + case I915_OVERLAY_YUV411: + return 1; + default: + return -EINVAL; } } @@ -588,7 +593,9 @@ static const u16 y_static_hcoeffs[N_HORIZ_Y_TAPS * N_PHASES] = { 0x3020, 0xb340, 0x1fb8, 0x34a0, 0xb060, 0x3020, 0xb240, 0x1fe0, 0x32e0, 0xb040, 0x3020, 0xb140, 0x1ff8, 0x3160, 0xb020, - 0xb000, 0x3000, 0x0800, 0x3000, 0xb000}; + 0xb000, 0x3000, 0x0800, 0x3000, 0xb000 +}; + static const u16 uv_static_hcoeffs[N_HORIZ_UV_TAPS * N_PHASES] = { 0x3000, 0x1800, 0x1800, 0xb000, 0x18d0, 0x2e60, 0xb000, 0x1990, 0x2ce0, 0xb020, 0x1a68, 0x2b40, @@ -598,7 +605,8 @@ static const u16 uv_static_hcoeffs[N_HORIZ_UV_TAPS * N_PHASES] = { 0xb100, 0x1eb8, 0x3620, 0xb100, 0x1f18, 0x34a0, 0xb100, 0x1f68, 0x3360, 0xb0e0, 0x1fa8, 0x3240, 0xb0c0, 0x1fe0, 0x3140, 0xb060, 0x1ff0, 0x30a0, - 0x3000, 0x0800, 0x3000}; + 0x3000, 0x0800, 0x3000 +}; static void update_polyphase_filter(struct overlay_registers *regs) { @@ -631,29 +639,31 @@ static bool update_scaling_factors(struct intel_overlay *overlay, yscale = 1 << FP_SHIFT; /*if (params->format & I915_OVERLAY_YUV_PLANAR) {*/ - xscale_UV = xscale/uv_hscale; - yscale_UV = yscale/uv_vscale; - /* make the Y scale to UV scale ratio an exact multiply */ - xscale = xscale_UV * uv_hscale; - yscale = yscale_UV * uv_vscale; + xscale_UV = xscale/uv_hscale; + yscale_UV = yscale/uv_vscale; + /* make the Y scale to UV scale ratio an exact multiply */ + xscale = xscale_UV * uv_hscale; + yscale = yscale_UV * uv_vscale; /*} else { - xscale_UV = 0; - yscale_UV = 0; - }*/ + xscale_UV = 0; + yscale_UV = 0; + }*/ if (xscale != overlay->old_xscale || yscale != overlay->old_yscale) scale_changed = true; overlay->old_xscale = xscale; overlay->old_yscale = yscale; - regs->YRGBSCALE = ((yscale & FRACT_MASK) << 20) - | ((xscale >> FP_SHIFT) << 16) - | ((xscale & FRACT_MASK) << 3); - regs->UVSCALE = ((yscale_UV & FRACT_MASK) << 20) - | ((xscale_UV >> FP_SHIFT) << 16) - | ((xscale_UV & FRACT_MASK) << 3); - regs->UVSCALEV = ((yscale >> FP_SHIFT) << 16) - | ((yscale_UV >> FP_SHIFT) << 0); + regs->YRGBSCALE = (((yscale & FRACT_MASK) << 20) | + ((xscale >> FP_SHIFT) << 16) | + ((xscale & FRACT_MASK) << 3)); + + regs->UVSCALE = (((yscale_UV & FRACT_MASK) << 20) | + ((xscale_UV >> FP_SHIFT) << 16) | + ((xscale_UV & FRACT_MASK) << 3)); + + regs->UVSCALEV = ((((yscale >> FP_SHIFT) << 16) | + ((yscale_UV >> FP_SHIFT) << 0))); if (scale_changed) update_polyphase_filter(regs); @@ -666,21 +676,21 @@ static void update_colorkey(struct intel_overlay *overlay, { u32 key = overlay->color_key; switch (overlay->crtc->base.fb->bits_per_pixel) { - case 8: - regs->DCLRKV = 0; - regs->DCLRKM = CLK_RGB8I_MASK | DST_KEY_ENABLE; - case 16: - if (overlay->crtc->base.fb->depth == 15) { - regs->DCLRKV = RGB15_TO_COLORKEY(key); - regs->DCLRKM = CLK_RGB15_MASK | DST_KEY_ENABLE; - } else { - regs->DCLRKV = RGB16_TO_COLORKEY(key); - regs->DCLRKM = CLK_RGB16_MASK | DST_KEY_ENABLE; - } - case 24: - case 32: - regs->DCLRKV = key; - regs->DCLRKM = CLK_RGB24_MASK | DST_KEY_ENABLE; + case 8: + regs->DCLRKV = 0; + regs->DCLRKM = CLK_RGB8I_MASK | DST_KEY_ENABLE; + case 16: + if (overlay->crtc->base.fb->depth == 15) { + regs->DCLRKV = RGB15_TO_COLORKEY(key); + regs->DCLRKM = CLK_RGB15_MASK | DST_KEY_ENABLE; + } else { + regs->DCLRKV = RGB16_TO_COLORKEY(key); + regs->DCLRKM = CLK_RGB16_MASK | DST_KEY_ENABLE; + } + case 24: + case 32: + regs->DCLRKV = key; + regs->DCLRKM = CLK_RGB24_MASK | DST_KEY_ENABLE; } } @@ -690,39 +700,39 @@ static u32 overlay_cmd_reg(struct put_image_params *params) if (params->format & I915_OVERLAY_YUV_PLANAR) { switch (params->format & I915_OVERLAY_DEPTH_MASK) { - case I915_OVERLAY_YUV422: - cmd |= OCMD_YUV_422_PLANAR; - break; - case I915_OVERLAY_YUV420: - cmd |= OCMD_YUV_420_PLANAR; - break; - case I915_OVERLAY_YUV411: - case I915_OVERLAY_YUV410: - cmd |= OCMD_YUV_410_PLANAR; - break; + case I915_OVERLAY_YUV422: + cmd |= OCMD_YUV_422_PLANAR; + break; + case I915_OVERLAY_YUV420: + cmd |= OCMD_YUV_420_PLANAR; + break; + case I915_OVERLAY_YUV411: + case I915_OVERLAY_YUV410: + cmd |= OCMD_YUV_410_PLANAR; + break; } } else { /* YUV packed */ switch (params->format & I915_OVERLAY_DEPTH_MASK) { - case I915_OVERLAY_YUV422: - cmd |= OCMD_YUV_422_PACKED; - break; - case I915_OVERLAY_YUV411: - cmd |= OCMD_YUV_411_PACKED; - break; + case I915_OVERLAY_YUV422: + cmd |= OCMD_YUV_422_PACKED; + break; + case I915_OVERLAY_YUV411: + cmd |= OCMD_YUV_411_PACKED; + break; } switch (params->format & I915_OVERLAY_SWAP_MASK) { - case I915_OVERLAY_NO_SWAP: - break; - case I915_OVERLAY_UV_SWAP: - cmd |= OCMD_UV_SWAP; - break; - case I915_OVERLAY_Y_SWAP: - cmd |= OCMD_Y_SWAP; - break; - case I915_OVERLAY_Y_AND_UV_SWAP: - cmd |= OCMD_Y_AND_UV_SWAP; - break; + case I915_OVERLAY_NO_SWAP: + break; + case I915_OVERLAY_UV_SWAP: + cmd |= OCMD_UV_SWAP; + break; + case I915_OVERLAY_Y_SWAP: + cmd |= OCMD_Y_SWAP; + break; + case I915_OVERLAY_Y_AND_UV_SWAP: + cmd |= OCMD_Y_AND_UV_SWAP; + break; } } @@ -789,7 +799,7 @@ int intel_overlay_do_put_image(struct intel_overlay *overlay, regs->SWIDTH = params->src_w; regs->SWIDTHSW = calc_swidthsw(overlay->dev, - params->offset_Y, tmp_width); + params->offset_Y, tmp_width); regs->SHEIGHT = params->src_h; regs->OBUF_0Y = bo_priv->gtt_offset + params-> offset_Y; regs->OSTRIDE = params->stride_Y; @@ -800,9 +810,9 @@ int intel_overlay_do_put_image(struct intel_overlay *overlay, u32 tmp_U, tmp_V; regs->SWIDTH |= (params->src_w/uv_hscale) << 16; tmp_U = calc_swidthsw(overlay->dev, params->offset_U, - params->src_w/uv_hscale); + params->src_w/uv_hscale); tmp_V = calc_swidthsw(overlay->dev, params->offset_V, - params->src_w/uv_hscale); + params->src_w/uv_hscale); regs->SWIDTHSW |= max_t(u32, tmp_U, tmp_V) << 16; regs->SHEIGHT |= (params->src_h/uv_vscale) << 16; regs->OBUF_0U = bo_priv->gtt_offset + params->offset_U; @@ -868,7 +878,7 @@ int intel_overlay_switch_off(struct intel_overlay *overlay) static int check_overlay_possible_on_crtc(struct intel_overlay *overlay, struct intel_crtc *crtc) { - drm_i915_private_t *dev_priv = overlay->dev->dev_private; + drm_i915_private_t *dev_priv = overlay->dev->dev_private; u32 pipeconf; int pipeconf_reg = (crtc->pipe == 0) ? PIPEACONF : PIPEBCONF; @@ -887,7 +897,7 @@ static int check_overlay_possible_on_crtc(struct intel_overlay *overlay, static void update_pfit_vscale_ratio(struct intel_overlay *overlay) { struct drm_device *dev = overlay->dev; - drm_i915_private_t *dev_priv = dev->dev_private; + drm_i915_private_t *dev_priv = dev->dev_private; u32 ratio; u32 pfit_control = I915_READ(PFIT_CONTROL); @@ -911,12 +921,10 @@ static int check_overlay_dst(struct intel_overlay *overlay, { struct drm_display_mode *mode = &overlay->crtc->base.mode; - if ((rec->dst_x < mode->crtc_hdisplay) - && (rec->dst_x + rec->dst_width - <= mode->crtc_hdisplay) - && (rec->dst_y < mode->crtc_vdisplay) - && (rec->dst_y + rec->dst_height - <= mode->crtc_vdisplay)) + if (rec->dst_x < mode->crtc_hdisplay && + rec->dst_x + rec->dst_width <= mode->crtc_hdisplay && + rec->dst_y < mode->crtc_vdisplay && + rec->dst_y + rec->dst_height <= mode->crtc_vdisplay) return 0; else return -EINVAL; @@ -949,45 +957,45 @@ static int check_overlay_src(struct drm_device *dev, /* check src dimensions */ if (IS_845G(dev) || IS_I830(dev)) { - if (rec->src_height > IMAGE_MAX_HEIGHT_LEGACY - || rec->src_width > IMAGE_MAX_WIDTH_LEGACY) + if (rec->src_height > IMAGE_MAX_HEIGHT_LEGACY || + rec->src_width > IMAGE_MAX_WIDTH_LEGACY) return -EINVAL; } else { - if (rec->src_height > IMAGE_MAX_HEIGHT - || rec->src_width > IMAGE_MAX_WIDTH) + if (rec->src_height > IMAGE_MAX_HEIGHT || + rec->src_width > IMAGE_MAX_WIDTH) return -EINVAL; } /* better safe than sorry, use 4 as the maximal subsampling ratio */ - if (rec->src_height < N_VERT_Y_TAPS*4 - || rec->src_width < N_HORIZ_Y_TAPS*4) + if (rec->src_height < N_VERT_Y_TAPS*4 || + rec->src_width < N_HORIZ_Y_TAPS*4) return -EINVAL; /* check alignment constraints */ switch (rec->flags & I915_OVERLAY_TYPE_MASK) { - case I915_OVERLAY_RGB: - /* not implemented */ + case I915_OVERLAY_RGB: + /* not implemented */ + return -EINVAL; + case I915_OVERLAY_YUV_PACKED: + depth = packed_depth_bytes(rec->flags); + if (uv_vscale != 1) return -EINVAL; - case I915_OVERLAY_YUV_PACKED: - depth = packed_depth_bytes(rec->flags); - if (uv_vscale != 1) - return -EINVAL; - if (depth < 0) - return depth; - /* ignore UV planes */ - rec->stride_UV = 0; - rec->offset_U = 0; - rec->offset_V = 0; - /* check pixel alignment */ - if (rec->offset_Y % depth) - return -EINVAL; - break; - case I915_OVERLAY_YUV_PLANAR: - if (uv_vscale < 0 || uv_hscale < 0) - return -EINVAL; - /* no offset restrictions for planar formats */ - break; - default: + if (depth < 0) + return depth; + /* ignore UV planes */ + rec->stride_UV = 0; + rec->offset_U = 0; + rec->offset_V = 0; + /* check pixel alignment */ + if (rec->offset_Y % depth) + return -EINVAL; + break; + case I915_OVERLAY_YUV_PLANAR: + if (uv_vscale < 0 || uv_hscale < 0) return -EINVAL; + /* no offset restrictions for planar formats */ + break; + default: + return -EINVAL; } if (rec->src_width % uv_hscale) @@ -1011,32 +1019,32 @@ static int check_overlay_src(struct drm_device *dev, /* check buffer dimensions */ switch (rec->flags & I915_OVERLAY_TYPE_MASK) { - case I915_OVERLAY_RGB: - case I915_OVERLAY_YUV_PACKED: - /* always 4 Y values per depth pixels */ - if (packed_width_bytes(rec->flags, rec->src_width) - > rec->stride_Y) - return -EINVAL; - - tmp = rec->stride_Y*rec->src_height; - if (rec->offset_Y + tmp > new_bo->size) - return -EINVAL; - break; - case I915_OVERLAY_YUV_PLANAR: - if (rec->src_width > rec->stride_Y) - return -EINVAL; - if (rec->src_width/uv_hscale > rec->stride_UV) - return -EINVAL; - - tmp = rec->stride_Y*rec->src_height; - if (rec->offset_Y + tmp > new_bo->size) - return -EINVAL; - tmp = rec->stride_UV*rec->src_height; - tmp /= uv_vscale; - if (rec->offset_U + tmp > new_bo->size - || rec->offset_V + tmp > new_bo->size) - return -EINVAL; - break; + case I915_OVERLAY_RGB: + case I915_OVERLAY_YUV_PACKED: + /* always 4 Y values per depth pixels */ + if (packed_width_bytes(rec->flags, rec->src_width) > rec->stride_Y) + return -EINVAL; + + tmp = rec->stride_Y*rec->src_height; + if (rec->offset_Y + tmp > new_bo->size) + return -EINVAL; + break; + + case I915_OVERLAY_YUV_PLANAR: + if (rec->src_width > rec->stride_Y) + return -EINVAL; + if (rec->src_width/uv_hscale > rec->stride_UV) + return -EINVAL; + + tmp = rec->stride_Y*rec->src_height; + if (rec->offset_Y + tmp > new_bo->size) + return -EINVAL; + tmp = rec->stride_UV*rec->src_height; + tmp /= uv_vscale; + if (rec->offset_U + tmp > new_bo->size || + rec->offset_V + tmp > new_bo->size) + return -EINVAL; + break; } return 0; @@ -1082,7 +1090,7 @@ int intel_overlay_put_image(struct drm_device *dev, void *data, return -ENOMEM; drmmode_obj = drm_mode_object_find(dev, put_image_rec->crtc_id, - DRM_MODE_OBJECT_CRTC); + DRM_MODE_OBJECT_CRTC); if (!drmmode_obj) { ret = -ENOENT; goto out_free; @@ -1090,7 +1098,7 @@ int intel_overlay_put_image(struct drm_device *dev, void *data, crtc = to_intel_crtc(obj_to_crtc(drmmode_obj)); new_bo = drm_gem_object_lookup(dev, file_priv, - put_image_rec->bo_handle); + put_image_rec->bo_handle); if (!new_bo) { ret = -ENOENT; goto out_free; @@ -1133,10 +1141,10 @@ int intel_overlay_put_image(struct drm_device *dev, void *data, if (overlay->pfit_active) { params->dst_y = ((((u32)put_image_rec->dst_y) << 12) / - overlay->pfit_vscale_ratio); + overlay->pfit_vscale_ratio); /* shifting right rounds downwards, so add 1 */ params->dst_h = ((((u32)put_image_rec->dst_height) << 12) / - overlay->pfit_vscale_ratio) + 1; + overlay->pfit_vscale_ratio) + 1; } else { params->dst_y = put_image_rec->dst_y; params->dst_h = put_image_rec->dst_height; @@ -1148,8 +1156,8 @@ int intel_overlay_put_image(struct drm_device *dev, void *data, params->src_h = put_image_rec->src_height; params->src_scan_w = put_image_rec->src_scan_width; params->src_scan_h = put_image_rec->src_scan_height; - if (params->src_scan_h > params->src_h - || params->src_scan_w > params->src_w) { + if (params->src_scan_h > params->src_h || + params->src_scan_w > params->src_w) { ret = -EINVAL; goto out_unlock; } @@ -1205,7 +1213,7 @@ static bool check_gamma_bounds(u32 gamma1, u32 gamma2) return false; for (i = 0; i < 3; i++) { - if (((gamma1 >> i * 8) & 0xff) >= ((gamma2 >> i*8) & 0xff)) + if (((gamma1 >> i*8) & 0xff) >= ((gamma2 >> i*8) & 0xff)) return false; } @@ -1226,16 +1234,18 @@ static bool check_gamma5_errata(u32 gamma5) static int check_gamma(struct drm_intel_overlay_attrs *attrs) { - if (!check_gamma_bounds(0, attrs->gamma0) - || !check_gamma_bounds(attrs->gamma0, attrs->gamma1) - || !check_gamma_bounds(attrs->gamma1, attrs->gamma2) - || !check_gamma_bounds(attrs->gamma2, attrs->gamma3) - || !check_gamma_bounds(attrs->gamma3, attrs->gamma4) - || !check_gamma_bounds(attrs->gamma4, attrs->gamma5) - || !check_gamma_bounds(attrs->gamma5, 0x00ffffff)) + if (!check_gamma_bounds(0, attrs->gamma0) || + !check_gamma_bounds(attrs->gamma0, attrs->gamma1) || + !check_gamma_bounds(attrs->gamma1, attrs->gamma2) || + !check_gamma_bounds(attrs->gamma2, attrs->gamma3) || + !check_gamma_bounds(attrs->gamma3, attrs->gamma4) || + !check_gamma_bounds(attrs->gamma4, attrs->gamma5) || + !check_gamma_bounds(attrs->gamma5, 0x00ffffff)) return -EINVAL; + if (!check_gamma5_errata(attrs->gamma5)) return -EINVAL; + return 0; } @@ -1285,12 +1295,14 @@ int intel_overlay_attrs(struct drm_device *dev, void *data, ret = -EINVAL; goto out_unlock; } + if (attrs->contrast <= 255) { overlay->contrast = attrs->contrast; } else { ret = -EINVAL; goto out_unlock; } + if (attrs->saturation <= 1023) { overlay->saturation = attrs->saturation; } else { @@ -1409,7 +1421,7 @@ out_free: void intel_cleanup_overlay(struct drm_device *dev) { - drm_i915_private_t *dev_priv = dev->dev_private; + drm_i915_private_t *dev_priv = dev->dev_private; if (dev_priv->overlay) { /* The bo's should be free'd by the generic code already. -- cgit v1.1 From 6ba3ddd9838f5e4d6ac7c6dce95648d205e11bff Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Thu, 12 Aug 2010 09:30:58 +0100 Subject: drm/i915/overlay: Missing breaks between case statements for color depth Signed-off-by: Chris Wilson Reviewed-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_overlay.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/drivers/gpu/drm/i915/intel_overlay.c b/drivers/gpu/drm/i915/intel_overlay.c index 5ed1783..4972b5c 100644 --- a/drivers/gpu/drm/i915/intel_overlay.c +++ b/drivers/gpu/drm/i915/intel_overlay.c @@ -675,10 +675,13 @@ static void update_colorkey(struct intel_overlay *overlay, struct overlay_registers *regs) { u32 key = overlay->color_key; + switch (overlay->crtc->base.fb->bits_per_pixel) { case 8: regs->DCLRKV = 0; regs->DCLRKM = CLK_RGB8I_MASK | DST_KEY_ENABLE; + break; + case 16: if (overlay->crtc->base.fb->depth == 15) { regs->DCLRKV = RGB15_TO_COLORKEY(key); @@ -687,10 +690,13 @@ static void update_colorkey(struct intel_overlay *overlay, regs->DCLRKV = RGB16_TO_COLORKEY(key); regs->DCLRKM = CLK_RGB16_MASK | DST_KEY_ENABLE; } + break; + case 24: case 32: regs->DCLRKV = key; regs->DCLRKM = CLK_RGB24_MASK | DST_KEY_ENABLE; + break; } } -- cgit v1.1 From 0ddc1289f3ffd779779ddd3922f26ae7d0a21604 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Thu, 12 Aug 2010 09:35:00 +0100 Subject: drm/i915/overlay: Ensure that the reg_bo is in the GTT prior to writing. Just makes sure that writes are not being aliased by the CPU cache and do make it out to main memory. Signed-off-by: Chris Wilson Reviewed-by: Daniel Vetter Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=24977 Cc: stable@kernel.org --- drivers/gpu/drm/i915/intel_overlay.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/drivers/gpu/drm/i915/intel_overlay.c b/drivers/gpu/drm/i915/intel_overlay.c index 4972b5c..fef4dd6 100644 --- a/drivers/gpu/drm/i915/intel_overlay.c +++ b/drivers/gpu/drm/i915/intel_overlay.c @@ -1386,6 +1386,12 @@ void intel_setup_overlay(struct drm_device *dev) goto out_free_bo; } overlay->flip_addr = overlay->reg_bo->gtt_offset; + + ret = i915_gem_object_set_to_gtt_domain(reg_bo, true); + if (ret) { + DRM_ERROR("failed to move overlay register bo into the GTT\n"); + goto out_unpin_bo; + } } else { ret = i915_gem_attach_phys_object(dev, reg_bo, I915_GEM_PHYS_OVERLAY_REGS, @@ -1418,6 +1424,8 @@ void intel_setup_overlay(struct drm_device *dev) DRM_INFO("initialized overlay support\n"); return; +out_unpin_bo: + i915_gem_object_unpin(reg_bo); out_free_bo: drm_gem_object_unreference(reg_bo); out_free: -- cgit v1.1 From 31578148b2c62612f9516fdcf5ebb64ab32ed12d Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Thu, 12 Aug 2010 09:42:51 +0100 Subject: drm/i915/overlay: Move capabilities bits to common info block. Signed-off-by: Chris Wilson Reviewed-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_drv.c | 12 +++++++++++ drivers/gpu/drm/i915/i915_drv.h | 5 +++++ drivers/gpu/drm/i915/intel_overlay.c | 40 +++++++++++++++++------------------- 3 files changed, 36 insertions(+), 21 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_drv.c b/drivers/gpu/drm/i915/i915_drv.c index 2879a76..dffc1bc 100644 --- a/drivers/gpu/drm/i915/i915_drv.c +++ b/drivers/gpu/drm/i915/i915_drv.c @@ -62,49 +62,60 @@ extern int intel_agp_enabled; static const struct intel_device_info intel_i830_info = { .gen = 2, .is_i8xx = 1, .is_mobile = 1, .cursor_needs_physical = 1, + .has_overlay = 1, .overlay_needs_physical = 1, }; static const struct intel_device_info intel_845g_info = { .gen = 2, .is_i8xx = 1, + .has_overlay = 1, .overlay_needs_physical = 1, }; static const struct intel_device_info intel_i85x_info = { .gen = 2, .is_i8xx = 1, .is_i85x = 1, .is_mobile = 1, .cursor_needs_physical = 1, + .has_overlay = 1, .overlay_needs_physical = 1, }; static const struct intel_device_info intel_i865g_info = { .gen = 2, .is_i8xx = 1, + .has_overlay = 1, .overlay_needs_physical = 1, }; static const struct intel_device_info intel_i915g_info = { .gen = 3, .is_i915g = 1, .is_i9xx = 1, .cursor_needs_physical = 1, + .has_overlay = 1, .overlay_needs_physical = 1, }; static const struct intel_device_info intel_i915gm_info = { .gen = 3, .is_i9xx = 1, .is_mobile = 1, .cursor_needs_physical = 1, + .has_overlay = 1, .overlay_needs_physical = 1, }; static const struct intel_device_info intel_i945g_info = { .gen = 3, .is_i9xx = 1, .has_hotplug = 1, .cursor_needs_physical = 1, + .has_overlay = 1, .overlay_needs_physical = 1, }; static const struct intel_device_info intel_i945gm_info = { .gen = 3, .is_i945gm = 1, .is_i9xx = 1, .is_mobile = 1, .has_hotplug = 1, .cursor_needs_physical = 1, + .has_overlay = 1, .overlay_needs_physical = 1, }; static const struct intel_device_info intel_i965g_info = { .gen = 4, .is_broadwater = 1, .is_i965g = 1, .is_i9xx = 1, .has_hotplug = 1, + .has_overlay = 1, }; static const struct intel_device_info intel_i965gm_info = { .gen = 4, .is_crestline = 1, .is_i965g = 1, .is_i965gm = 1, .is_i9xx = 1, .is_mobile = 1, .has_fbc = 1, .has_rc6 = 1, .has_hotplug = 1, + .has_overlay = 1, }; static const struct intel_device_info intel_g33_info = { .gen = 3, .is_g33 = 1, .is_i9xx = 1, .need_gfx_hws = 1, .has_hotplug = 1, + .has_overlay = 1, }; static const struct intel_device_info intel_g45_info = { @@ -121,6 +132,7 @@ 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, .is_i9xx = 1, .need_gfx_hws = 1, .has_hotplug = 1, + .has_overlay = 1, }; static const struct intel_device_info intel_ironlake_d_info = { diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index f983130..10c9e41 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -213,6 +213,8 @@ struct intel_device_info { u8 has_pipe_cxsr : 1; u8 has_hotplug : 1; u8 cursor_needs_physical : 1; + u8 has_overlay : 1; + u8 overlay_needs_physical : 1; }; enum no_fbc_reason { @@ -1218,6 +1220,9 @@ static inline void i915_write(struct drm_i915_private *dev_priv, u32 reg, #define HAS_BSD(dev) (IS_IRONLAKE(dev) || IS_G4X(dev)) #define I915_NEED_GFX_HWS(dev) (INTEL_INFO(dev)->need_gfx_hws) +#define HAS_OVERLAY(dev) (INTEL_INFO(dev)->has_overlay) +#define OVERLAY_NEEDS_PHYSICAL(dev) (INTEL_INFO(dev)->overlay_needs_physical) + /* With the 945 and later, Y tiling got adjusted so that it was 32 128-byte * rows, which changed the alignment requirements and fence programming. */ diff --git a/drivers/gpu/drm/i915/intel_overlay.c b/drivers/gpu/drm/i915/intel_overlay.c index fef4dd6..df5277a 100644 --- a/drivers/gpu/drm/i915/intel_overlay.c +++ b/drivers/gpu/drm/i915/intel_overlay.c @@ -173,9 +173,6 @@ struct overlay_registers { /* overlay flip addr flag */ #define OFC_UPDATE 0x1 -#define OVERLAY_NONPHYSICAL(dev) (IS_G33(dev) || IS_I965G(dev)) -#define OVERLAY_EXISTS(dev) (!IS_G4X(dev) && !IS_IRONLAKE(dev) && !IS_GEN6(dev)) - static struct overlay_registers *intel_overlay_map_regs_atomic(struct intel_overlay *overlay) { drm_i915_private_t *dev_priv = overlay->dev->dev_private; @@ -184,7 +181,9 @@ static struct overlay_registers *intel_overlay_map_regs_atomic(struct intel_over /* no recursive mappings */ BUG_ON(overlay->virt_addr); - if (OVERLAY_NONPHYSICAL(overlay->dev)) { + if (OVERLAY_NEEDS_PHYSICAL(overlay->dev)) { + regs = overlay->reg_bo->phys_obj->handle->vaddr; + } else { regs = io_mapping_map_atomic_wc(dev_priv->mm.gtt_mapping, overlay->reg_bo->gtt_offset, KM_USER0); @@ -193,15 +192,14 @@ static struct overlay_registers *intel_overlay_map_regs_atomic(struct intel_over DRM_ERROR("failed to map overlay regs in GTT\n"); return NULL; } - } else - regs = overlay->reg_bo->phys_obj->handle->vaddr; + } return overlay->virt_addr = regs; } static void intel_overlay_unmap_regs_atomic(struct intel_overlay *overlay) { - if (OVERLAY_NONPHYSICAL(overlay->dev)) + if (!OVERLAY_NEEDS_PHYSICAL(overlay->dev)) io_mapping_unmap_atomic(overlay->virt_addr, KM_USER0); overlay->virt_addr = NULL; @@ -1366,7 +1364,7 @@ void intel_setup_overlay(struct drm_device *dev) struct overlay_registers *regs; int ret; - if (!OVERLAY_EXISTS(dev)) + if (!HAS_OVERLAY(dev)) return; overlay = kzalloc(sizeof(struct intel_overlay), GFP_KERNEL); @@ -1379,7 +1377,16 @@ void intel_setup_overlay(struct drm_device *dev) goto out_free; overlay->reg_bo = to_intel_bo(reg_bo); - if (OVERLAY_NONPHYSICAL(dev)) { + if (OVERLAY_NEEDS_PHYSICAL(dev)) { + ret = i915_gem_attach_phys_object(dev, reg_bo, + I915_GEM_PHYS_OVERLAY_REGS, + 0); + if (ret) { + DRM_ERROR("failed to attach phys overlay regs\n"); + goto out_free_bo; + } + overlay->flip_addr = overlay->reg_bo->phys_obj->handle->busaddr; + } else { ret = i915_gem_object_pin(reg_bo, PAGE_SIZE); if (ret) { DRM_ERROR("failed to pin overlay register bo\n"); @@ -1392,15 +1399,6 @@ void intel_setup_overlay(struct drm_device *dev) DRM_ERROR("failed to move overlay register bo into the GTT\n"); goto out_unpin_bo; } - } else { - ret = i915_gem_attach_phys_object(dev, reg_bo, - I915_GEM_PHYS_OVERLAY_REGS, - 0); - if (ret) { - DRM_ERROR("failed to attach phys overlay regs\n"); - goto out_free_bo; - } - overlay->flip_addr = overlay->reg_bo->phys_obj->handle->busaddr; } /* init all values */ @@ -1471,10 +1469,10 @@ intel_overlay_capture_error_state(struct drm_device *dev) error->dovsta = I915_READ(DOVSTA); error->isr = I915_READ(ISR); - if (OVERLAY_NONPHYSICAL(overlay->dev)) - error->base = (long) overlay->reg_bo->gtt_offset; - else + if (OVERLAY_NEEDS_PHYSICAL(overlay->dev)) error->base = (long) overlay->reg_bo->phys_obj->handle->vaddr; + else + error->base = (long) overlay->reg_bo->gtt_offset; regs = intel_overlay_map_regs_atomic(overlay); if (!regs) -- cgit v1.1 From 8d74f656dd78ae1ba813389cd46197c6329696bc Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Thu, 12 Aug 2010 10:35:26 +0100 Subject: drm/i915/overlay: Use non-atomic mappings for the common case. The only time where an atomic mapping is required is during error-capture and there we cannot use the default slot, but need to specifically use one of the IRQ slots. So separate out the two conditions and use the atomic mapping only when appropriate. Signed-off-by: Chris Wilson Reviewed-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_overlay.c | 72 +++++++++++++++++++++++++++--------- 1 file changed, 55 insertions(+), 17 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_overlay.c b/drivers/gpu/drm/i915/intel_overlay.c index df5277a..0c13e1b 100644 --- a/drivers/gpu/drm/i915/intel_overlay.c +++ b/drivers/gpu/drm/i915/intel_overlay.c @@ -173,7 +173,9 @@ struct overlay_registers { /* overlay flip addr flag */ #define OFC_UPDATE 0x1 -static struct overlay_registers *intel_overlay_map_regs_atomic(struct intel_overlay *overlay) +static struct overlay_registers * +intel_overlay_map_regs_atomic(struct intel_overlay *overlay, + int slot) { drm_i915_private_t *dev_priv = overlay->dev->dev_private; struct overlay_registers *regs; @@ -186,7 +188,7 @@ static struct overlay_registers *intel_overlay_map_regs_atomic(struct intel_over } else { regs = io_mapping_map_atomic_wc(dev_priv->mm.gtt_mapping, overlay->reg_bo->gtt_offset, - KM_USER0); + slot); if (!regs) { DRM_ERROR("failed to map overlay regs in GTT\n"); @@ -197,10 +199,45 @@ static struct overlay_registers *intel_overlay_map_regs_atomic(struct intel_over return overlay->virt_addr = regs; } -static void intel_overlay_unmap_regs_atomic(struct intel_overlay *overlay) +static void intel_overlay_unmap_regs_atomic(struct intel_overlay *overlay, + int slot) { if (!OVERLAY_NEEDS_PHYSICAL(overlay->dev)) - io_mapping_unmap_atomic(overlay->virt_addr, KM_USER0); + io_mapping_unmap_atomic(overlay->virt_addr, slot); + + overlay->virt_addr = NULL; + + return; +} + +static struct overlay_registers * +intel_overlay_map_regs(struct intel_overlay *overlay) +{ + drm_i915_private_t *dev_priv = overlay->dev->dev_private; + struct overlay_registers *regs; + + /* no recursive mappings */ + BUG_ON(overlay->virt_addr); + + if (OVERLAY_NEEDS_PHYSICAL(overlay->dev)) { + regs = overlay->reg_bo->phys_obj->handle->vaddr; + } else { + regs = io_mapping_map_wc(dev_priv->mm.gtt_mapping, + overlay->reg_bo->gtt_offset); + + if (!regs) { + DRM_ERROR("failed to map overlay regs in GTT\n"); + return NULL; + } + } + + return overlay->virt_addr = regs; +} + +static void intel_overlay_unmap_regs(struct intel_overlay *overlay) +{ + if (!OVERLAY_NEEDS_PHYSICAL(overlay->dev)) + io_mapping_unmap(overlay->virt_addr); overlay->virt_addr = NULL; @@ -467,7 +504,8 @@ int intel_overlay_recover_from_interrupt(struct intel_overlay *overlay, /* Wait for pending overlay flip and release old frame. * Needs to be called before the overlay register are changed - * via intel_overlay_(un)map_regs_atomic */ + * via intel_overlay_(un)map_regs + */ static int intel_overlay_release_old_vid(struct intel_overlay *overlay) { int ret; @@ -770,7 +808,7 @@ int intel_overlay_do_put_image(struct intel_overlay *overlay, goto out_unpin; if (!overlay->active) { - regs = intel_overlay_map_regs_atomic(overlay); + regs = intel_overlay_map_regs(overlay); if (!regs) { ret = -ENOMEM; goto out_unpin; @@ -780,14 +818,14 @@ int intel_overlay_do_put_image(struct intel_overlay *overlay, regs->OCONFIG |= OCONF_CSC_MODE_BT709; regs->OCONFIG |= overlay->crtc->pipe == 0 ? OCONF_PIPE_A : OCONF_PIPE_B; - intel_overlay_unmap_regs_atomic(overlay); + intel_overlay_unmap_regs(overlay); ret = intel_overlay_on(overlay); if (ret != 0) goto out_unpin; } - regs = intel_overlay_map_regs_atomic(overlay); + regs = intel_overlay_map_regs(overlay); if (!regs) { ret = -ENOMEM; goto out_unpin; @@ -830,7 +868,7 @@ int intel_overlay_do_put_image(struct intel_overlay *overlay, regs->OCMD = overlay_cmd_reg(params); - intel_overlay_unmap_regs_atomic(overlay); + intel_overlay_unmap_regs(overlay); intel_overlay_continue(overlay, scale_changed); @@ -866,9 +904,9 @@ int intel_overlay_switch_off(struct intel_overlay *overlay) if (ret != 0) return ret; - regs = intel_overlay_map_regs_atomic(overlay); + regs = intel_overlay_map_regs(overlay); regs->OCMD = 0; - intel_overlay_unmap_regs_atomic(overlay); + intel_overlay_unmap_regs(overlay); ret = intel_overlay_off(overlay); if (ret != 0) @@ -1314,7 +1352,7 @@ int intel_overlay_attrs(struct drm_device *dev, void *data, goto out_unlock; } - regs = intel_overlay_map_regs_atomic(overlay); + regs = intel_overlay_map_regs(overlay); if (!regs) { ret = -ENOMEM; goto out_unlock; @@ -1322,7 +1360,7 @@ int intel_overlay_attrs(struct drm_device *dev, void *data, update_reg_attrs(overlay, regs); - intel_overlay_unmap_regs_atomic(overlay); + intel_overlay_unmap_regs(overlay); if (attrs->flags & I915_OVERLAY_UPDATE_GAMMA) { if (!IS_I9XX(dev)) { @@ -1407,7 +1445,7 @@ void intel_setup_overlay(struct drm_device *dev) overlay->contrast = 75; overlay->saturation = 146; - regs = intel_overlay_map_regs_atomic(overlay); + regs = intel_overlay_map_regs(overlay); if (!regs) goto out_free_bo; @@ -1416,7 +1454,7 @@ void intel_setup_overlay(struct drm_device *dev) update_reg_attrs(overlay, regs); - intel_overlay_unmap_regs_atomic(overlay); + intel_overlay_unmap_regs(overlay); dev_priv->overlay = overlay; DRM_INFO("initialized overlay support\n"); @@ -1474,12 +1512,12 @@ intel_overlay_capture_error_state(struct drm_device *dev) else error->base = (long) overlay->reg_bo->gtt_offset; - regs = intel_overlay_map_regs_atomic(overlay); + regs = intel_overlay_map_regs_atomic(overlay, KM_IRQ0); if (!regs) goto err; memcpy_fromio(&error->regs, regs, sizeof(struct overlay_registers)); - intel_overlay_unmap_regs_atomic(overlay); + intel_overlay_unmap_regs_atomic(overlay, KM_IRQ0); return error; -- cgit v1.1 From 60fc332cb5ab19e5a86d696b210df65814b2ad8a Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Thu, 12 Aug 2010 10:44:45 +0100 Subject: drm/i915/overlay: Tidy attribute checking. Signed-off-by: Chris Wilson Reviewed-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_overlay.c | 40 +++++++++++++----------------------- 1 file changed, 14 insertions(+), 26 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_overlay.c b/drivers/gpu/drm/i915/intel_overlay.c index 0c13e1b..ab2a8ca 100644 --- a/drivers/gpu/drm/i915/intel_overlay.c +++ b/drivers/gpu/drm/i915/intel_overlay.c @@ -1314,10 +1314,11 @@ int intel_overlay_attrs(struct drm_device *dev, void *data, mutex_lock(&dev->mode_config.mutex); mutex_lock(&dev->struct_mutex); + ret = -EINVAL; if (!(attrs->flags & I915_OVERLAY_UPDATE_ATTRS)) { - attrs->color_key = overlay->color_key; + attrs->color_key = overlay->color_key; attrs->brightness = overlay->brightness; - attrs->contrast = overlay->contrast; + attrs->contrast = overlay->contrast; attrs->saturation = overlay->saturation; if (IS_I9XX(dev)) { @@ -1328,29 +1329,18 @@ int intel_overlay_attrs(struct drm_device *dev, void *data, attrs->gamma4 = I915_READ(OGAMC4); attrs->gamma5 = I915_READ(OGAMC5); } - ret = 0; } else { - overlay->color_key = attrs->color_key; - if (attrs->brightness >= -128 && attrs->brightness <= 127) { - overlay->brightness = attrs->brightness; - } else { - ret = -EINVAL; + if (attrs->brightness < -128 || attrs->brightness > 127) goto out_unlock; - } - - if (attrs->contrast <= 255) { - overlay->contrast = attrs->contrast; - } else { - ret = -EINVAL; + if (attrs->contrast > 255) goto out_unlock; - } - - if (attrs->saturation <= 1023) { - overlay->saturation = attrs->saturation; - } else { - ret = -EINVAL; + if (attrs->saturation > 1023) goto out_unlock; - } + + overlay->color_key = attrs->color_key; + overlay->brightness = attrs->brightness; + overlay->contrast = attrs->contrast; + overlay->saturation = attrs->saturation; regs = intel_overlay_map_regs(overlay); if (!regs) { @@ -1363,10 +1353,8 @@ int intel_overlay_attrs(struct drm_device *dev, void *data, intel_overlay_unmap_regs(overlay); if (attrs->flags & I915_OVERLAY_UPDATE_GAMMA) { - if (!IS_I9XX(dev)) { - ret = -EINVAL; + if (!IS_I9XX(dev)) goto out_unlock; - } if (overlay->active) { ret = -EBUSY; @@ -1374,7 +1362,7 @@ int intel_overlay_attrs(struct drm_device *dev, void *data, } ret = check_gamma(attrs); - if (ret != 0) + if (ret) goto out_unlock; I915_WRITE(OGAMC0, attrs->gamma0); @@ -1384,9 +1372,9 @@ int intel_overlay_attrs(struct drm_device *dev, void *data, I915_WRITE(OGAMC4, attrs->gamma4); I915_WRITE(OGAMC5, attrs->gamma5); } - ret = 0; } + ret = 0; out_unlock: mutex_unlock(&dev->struct_mutex); mutex_unlock(&dev->mode_config.mutex); -- cgit v1.1 From a29301288f1840bdf9c5456da9cd7c944436edd5 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Thu, 12 Aug 2010 10:47:56 +0100 Subject: drm/i915/overlay: Use the recommended page alignment for physical regs Signed-off-by: Chris Wilson Reviewed-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_overlay.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/intel_overlay.c b/drivers/gpu/drm/i915/intel_overlay.c index ab2a8ca..b0aea47 100644 --- a/drivers/gpu/drm/i915/intel_overlay.c +++ b/drivers/gpu/drm/i915/intel_overlay.c @@ -1406,7 +1406,7 @@ void intel_setup_overlay(struct drm_device *dev) if (OVERLAY_NEEDS_PHYSICAL(dev)) { ret = i915_gem_attach_phys_object(dev, reg_bo, I915_GEM_PHYS_OVERLAY_REGS, - 0); + PAGE_SIZE); if (ret) { DRM_ERROR("failed to attach phys overlay regs\n"); goto out_free_bo; -- cgit v1.1 From 62cf4e6fef35b4422e206b63b7f0ac90261d4ad9 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Thu, 12 Aug 2010 10:50:36 +0100 Subject: drm/i915/overlay: Destroy reg_bo on shutdown. Signed-off-by: Chris Wilson Reviewed-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_overlay.c | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_overlay.c b/drivers/gpu/drm/i915/intel_overlay.c index b0aea47..3236cca 100644 --- a/drivers/gpu/drm/i915/intel_overlay.c +++ b/drivers/gpu/drm/i915/intel_overlay.c @@ -1461,14 +1461,16 @@ void intel_cleanup_overlay(struct drm_device *dev) { drm_i915_private_t *dev_priv = dev->dev_private; - if (dev_priv->overlay) { - /* The bo's should be free'd by the generic code already. - * Furthermore modesetting teardown happens beforehand so the - * hardware should be off already */ - BUG_ON(dev_priv->overlay->active); + if (!dev_priv->overlay) + return; - kfree(dev_priv->overlay); - } + /* The bo's should be free'd by the generic code already. + * Furthermore modesetting teardown happens beforehand so the + * hardware should be off already */ + BUG_ON(dev_priv->overlay->active); + + drm_gem_object_unreference_unlocked(&dev_priv->overlay->reg_bo->base); + kfree(dev_priv->overlay); } struct intel_overlay_error_state { -- cgit v1.1 From 7340ea7dcf32227a77ed9df154fc2b2f00ad2fb1 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Thu, 12 Aug 2010 10:57:04 +0100 Subject: drm/i915/overlay: Remove duplicated definition of OFC_UPDATE Signed-off-by: Chris Wilson Reviewed-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_overlay.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_overlay.c b/drivers/gpu/drm/i915/intel_overlay.c index 3236cca..cc86b3e 100644 --- a/drivers/gpu/drm/i915/intel_overlay.c +++ b/drivers/gpu/drm/i915/intel_overlay.c @@ -170,9 +170,6 @@ struct overlay_registers { u16 RESERVEDG[0x100 / 2 - N_HORIZ_UV_TAPS * N_PHASES]; }; -/* overlay flip addr flag */ -#define OFC_UPDATE 0x1 - static struct overlay_registers * intel_overlay_map_regs_atomic(struct intel_overlay *overlay, int slot) -- cgit v1.1 From 446d2183af68c0fd2772f5ef97a033efe69904a5 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Thu, 12 Aug 2010 11:15:58 +0100 Subject: drm/i915/overlay: Tidy update_pfit_vscale_ratio() Signed-off-by: Chris Wilson Reviewed-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_overlay.c | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_overlay.c b/drivers/gpu/drm/i915/intel_overlay.c index cc86b3e..4840582 100644 --- a/drivers/gpu/drm/i915/intel_overlay.c +++ b/drivers/gpu/drm/i915/intel_overlay.c @@ -937,19 +937,20 @@ static void update_pfit_vscale_ratio(struct intel_overlay *overlay) { struct drm_device *dev = overlay->dev; drm_i915_private_t *dev_priv = dev->dev_private; - u32 ratio; u32 pfit_control = I915_READ(PFIT_CONTROL); + u32 ratio; /* XXX: This is not the same logic as in the xorg driver, but more in - * line with the intel documentation for the i965 */ - if (!IS_I965G(dev) && (pfit_control & VERT_AUTO_SCALE)) { - ratio = I915_READ(PFIT_AUTO_RATIOS) >> PFIT_VERT_SCALE_SHIFT; - } else { /* on i965 use the PGM reg to read out the autoscaler values */ - ratio = I915_READ(PFIT_PGM_RATIOS); - if (IS_I965G(dev)) - ratio >>= PFIT_VERT_SCALE_SHIFT_965; + * line with the intel documentation for the i965 + */ + if (!IS_I965G(dev)) { + if (pfit_control & VERT_AUTO_SCALE) + ratio = I915_READ(PFIT_AUTO_RATIOS); else - ratio >>= PFIT_VERT_SCALE_SHIFT; + ratio = I915_READ(PFIT_PGM_RATIOS); + ratio >>= PFIT_VERT_SCALE_SHIFT; + } else { /* on i965 use the PGM reg to read out the autoscaler values */ + ratio = I915_READ(PFIT_PGM_RATIOS) >> PFIT_VERT_SCALE_SHIFT_965; } overlay->pfit_vscale_ratio = ratio; -- cgit v1.1 From 9f7c3f442bb7c0d0a0ed25cc287932450a1f2bab Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Thu, 12 Aug 2010 11:29:34 +0100 Subject: drm/i915/overlay: Tidy check_overlay_dst() Signed-off-by: Chris Wilson Reviewed-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_overlay.c | 28 ++++++++++++++++------------ 1 file changed, 16 insertions(+), 12 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_overlay.c b/drivers/gpu/drm/i915/intel_overlay.c index 4840582..7fbc0f3 100644 --- a/drivers/gpu/drm/i915/intel_overlay.c +++ b/drivers/gpu/drm/i915/intel_overlay.c @@ -989,25 +989,24 @@ static int check_overlay_src(struct drm_device *dev, struct drm_intel_overlay_put_image *rec, struct drm_gem_object *new_bo) { - u32 stride_mask; - int depth; int uv_hscale = uv_hsubsampling(rec->flags); int uv_vscale = uv_vsubsampling(rec->flags); - size_t tmp; + u32 stride_mask, depth, tmp; /* check src dimensions */ if (IS_845G(dev) || IS_I830(dev)) { if (rec->src_height > IMAGE_MAX_HEIGHT_LEGACY || - rec->src_width > IMAGE_MAX_WIDTH_LEGACY) + rec->src_width > IMAGE_MAX_WIDTH_LEGACY) return -EINVAL; } else { if (rec->src_height > IMAGE_MAX_HEIGHT || - rec->src_width > IMAGE_MAX_WIDTH) + rec->src_width > IMAGE_MAX_WIDTH) return -EINVAL; } + /* better safe than sorry, use 4 as the maximal subsampling ratio */ if (rec->src_height < N_VERT_Y_TAPS*4 || - rec->src_width < N_HORIZ_Y_TAPS*4) + rec->src_width < N_HORIZ_Y_TAPS*4) return -EINVAL; /* check alignment constraints */ @@ -1015,12 +1014,15 @@ static int check_overlay_src(struct drm_device *dev, case I915_OVERLAY_RGB: /* not implemented */ return -EINVAL; + case I915_OVERLAY_YUV_PACKED: - depth = packed_depth_bytes(rec->flags); if (uv_vscale != 1) return -EINVAL; + + depth = packed_depth_bytes(rec->flags); if (depth < 0) return depth; + /* ignore UV planes */ rec->stride_UV = 0; rec->offset_U = 0; @@ -1029,11 +1031,13 @@ static int check_overlay_src(struct drm_device *dev, if (rec->offset_Y % depth) return -EINVAL; break; + case I915_OVERLAY_YUV_PLANAR: if (uv_vscale < 0 || uv_hscale < 0) return -EINVAL; /* no offset restrictions for planar formats */ break; + default: return -EINVAL; } @@ -1053,8 +1057,8 @@ static int check_overlay_src(struct drm_device *dev, return -EINVAL; tmp = (rec->flags & I915_OVERLAY_TYPE_MASK) == I915_OVERLAY_YUV_PLANAR ? - 4 : 8; - if (rec->stride_Y > tmp*1024 || rec->stride_UV > 2*1024) + 4096 : 8192; + if (rec->stride_Y > tmp || rec->stride_UV > 2*1024) return -EINVAL; /* check buffer dimensions */ @@ -1076,11 +1080,11 @@ static int check_overlay_src(struct drm_device *dev, if (rec->src_width/uv_hscale > rec->stride_UV) return -EINVAL; - tmp = rec->stride_Y*rec->src_height; + tmp = rec->stride_Y * rec->src_height; if (rec->offset_Y + tmp > new_bo->size) return -EINVAL; - tmp = rec->stride_UV*rec->src_height; - tmp /= uv_vscale; + + tmp = rec->stride_UV * (rec->src_height / uv_vscale); if (rec->offset_U + tmp > new_bo->size || rec->offset_V + tmp > new_bo->size) return -EINVAL; -- cgit v1.1 From b6c028e00445de9dfde2cd0c26521ac53965320a Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Thu, 12 Aug 2010 11:55:08 +0100 Subject: drm/i915/overlay: Refactor do_wait_request() Signed-off-by: Chris Wilson Reviewed-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_overlay.c | 117 +++++++++++------------------------ 1 file changed, 37 insertions(+), 80 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_overlay.c b/drivers/gpu/drm/i915/intel_overlay.c index 7fbc0f3..7055c46 100644 --- a/drivers/gpu/drm/i915/intel_overlay.c +++ b/drivers/gpu/drm/i915/intel_overlay.c @@ -241,34 +241,24 @@ static void intel_overlay_unmap_regs(struct intel_overlay *overlay) return; } -/* overlay needs to be disable in OCMD reg */ -static int intel_overlay_on(struct intel_overlay *overlay) +static int intel_overlay_do_wait_request(struct intel_overlay *overlay, + bool interruptible, + int stage) { struct drm_device *dev = overlay->dev; - int ret; drm_i915_private_t *dev_priv = dev->dev_private; - - BUG_ON(overlay->active); - - overlay->active = 1; - overlay->hw_wedged = NEEDS_WAIT_FOR_FLIP; - - BEGIN_LP_RING(4); - OUT_RING(MI_OVERLAY_FLIP | MI_OVERLAY_ON); - OUT_RING(overlay->flip_addr | OFC_UPDATE); - OUT_RING(MI_WAIT_FOR_EVENT | MI_WAIT_FOR_OVERLAY_FLIP); - OUT_RING(MI_NOOP); - ADVANCE_LP_RING(); + int ret; overlay->last_flip_req = i915_add_request(dev, NULL, &dev_priv->render_ring); if (overlay->last_flip_req == 0) return -ENOMEM; + overlay->hw_wedged = stage; ret = i915_do_wait_request(dev, overlay->last_flip_req, true, &dev_priv->render_ring); - if (ret != 0) + if (ret) return ret; overlay->hw_wedged = 0; @@ -276,6 +266,26 @@ static int intel_overlay_on(struct intel_overlay *overlay) return 0; } +/* overlay needs to be disable in OCMD reg */ +static int intel_overlay_on(struct intel_overlay *overlay) +{ + struct drm_device *dev = overlay->dev; + + BUG_ON(overlay->active); + + overlay->active = 1; + + BEGIN_LP_RING(4); + OUT_RING(MI_OVERLAY_FLIP | MI_OVERLAY_ON); + OUT_RING(overlay->flip_addr | OFC_UPDATE); + OUT_RING(MI_WAIT_FOR_EVENT | MI_WAIT_FOR_OVERLAY_FLIP); + OUT_RING(MI_NOOP); + ADVANCE_LP_RING(); + + return intel_overlay_do_wait_request(overlay, true, + NEEDS_WAIT_FOR_FLIP); +} + /* overlay needs to be enabled in OCMD reg */ static void intel_overlay_continue(struct intel_overlay *overlay, bool load_polyphase_filter) @@ -326,27 +336,12 @@ static int intel_overlay_wait_flip(struct intel_overlay *overlay) } /* synchronous slowpath */ - overlay->hw_wedged = RELEASE_OLD_VID; - BEGIN_LP_RING(2); OUT_RING(MI_WAIT_FOR_EVENT | MI_WAIT_FOR_OVERLAY_FLIP); OUT_RING(MI_NOOP); ADVANCE_LP_RING(); - overlay->last_flip_req = - i915_add_request(dev, NULL, &dev_priv->render_ring); - if (overlay->last_flip_req == 0) - return -ENOMEM; - - ret = i915_do_wait_request(dev, - overlay->last_flip_req, true, - &dev_priv->render_ring); - if (ret != 0) - return ret; - - overlay->hw_wedged = 0; - overlay->last_flip_req = 0; - return 0; + return intel_overlay_do_wait_request(overlay, true, RELEASE_OLD_VID); } /* overlay needs to be disabled in OCMD reg */ @@ -354,7 +349,6 @@ static int intel_overlay_off(struct intel_overlay *overlay) { u32 flip_addr = overlay->flip_addr; struct drm_device *dev = overlay->dev; - drm_i915_private_t *dev_priv = dev->dev_private; int ret; BUG_ON(!overlay->active); @@ -366,8 +360,6 @@ static int intel_overlay_off(struct intel_overlay *overlay) flip_addr |= OFC_UPDATE; /* wait for overlay to go idle */ - overlay->hw_wedged = SWITCH_OFF_STAGE_1; - BEGIN_LP_RING(4); OUT_RING(MI_OVERLAY_FLIP | MI_OVERLAY_CONTINUE); OUT_RING(flip_addr); @@ -375,20 +367,12 @@ static int intel_overlay_off(struct intel_overlay *overlay) OUT_RING(MI_NOOP); ADVANCE_LP_RING(); - overlay->last_flip_req = - i915_add_request(dev, NULL, &dev_priv->render_ring); - if (overlay->last_flip_req == 0) - return -ENOMEM; - - ret = i915_do_wait_request(dev, - overlay->last_flip_req, true, - &dev_priv->render_ring); - if (ret != 0) + ret = intel_overlay_do_wait_request(overlay, true, + SWITCH_OFF_STAGE_1); + if (ret) return ret; /* turn overlay off */ - overlay->hw_wedged = SWITCH_OFF_STAGE_2; - BEGIN_LP_RING(4); OUT_RING(MI_OVERLAY_FLIP | MI_OVERLAY_OFF); OUT_RING(flip_addr); @@ -396,20 +380,8 @@ static int intel_overlay_off(struct intel_overlay *overlay) OUT_RING(MI_NOOP); ADVANCE_LP_RING(); - overlay->last_flip_req = - i915_add_request(dev, NULL, &dev_priv->render_ring); - if (overlay->last_flip_req == 0) - return -ENOMEM; - - ret = i915_do_wait_request(dev, - overlay->last_flip_req, true, - &dev_priv->render_ring); - if (ret != 0) - return ret; - - overlay->hw_wedged = 0; - overlay->last_flip_req = 0; - return ret; + return intel_overlay_do_wait_request(overlay, true, + SWITCH_OFF_STAGE_2); } static void intel_overlay_off_tail(struct intel_overlay *overlay) @@ -443,16 +415,9 @@ int intel_overlay_recover_from_interrupt(struct intel_overlay *overlay, if (overlay->hw_wedged == HW_WEDGED) return -EIO; - if (overlay->last_flip_req == 0) { - overlay->last_flip_req = - i915_add_request(dev, NULL, &dev_priv->render_ring); - if (overlay->last_flip_req == 0) - return -ENOMEM; - } - ret = i915_do_wait_request(dev, overlay->last_flip_req, interruptible, &dev_priv->render_ring); - if (ret != 0) + if (ret) return ret; switch (overlay->hw_wedged) { @@ -462,12 +427,11 @@ int intel_overlay_recover_from_interrupt(struct intel_overlay *overlay, drm_gem_object_unreference(obj); overlay->old_vid_bo = NULL; break; + case SWITCH_OFF_STAGE_1: flip_addr = overlay->flip_addr; flip_addr |= OFC_UPDATE; - overlay->hw_wedged = SWITCH_OFF_STAGE_2; - BEGIN_LP_RING(4); OUT_RING(MI_OVERLAY_FLIP | MI_OVERLAY_OFF); OUT_RING(flip_addr); @@ -475,16 +439,9 @@ int intel_overlay_recover_from_interrupt(struct intel_overlay *overlay, OUT_RING(MI_NOOP); ADVANCE_LP_RING(); - overlay->last_flip_req = - i915_add_request(dev, NULL, - &dev_priv->render_ring); - if (overlay->last_flip_req == 0) - return -ENOMEM; - - ret = i915_do_wait_request(dev, overlay->last_flip_req, - interruptible, - &dev_priv->render_ring); - if (ret != 0) + ret = intel_overlay_do_wait_request(overlay, interruptible, + SWITCH_OFF_STAGE_2); + if (ret) return ret; case SWITCH_OFF_STAGE_2: -- cgit v1.1 From 9bb2ff731b32c023e7a502efdc0dee46157290d5 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Thu, 12 Aug 2010 12:02:11 +0100 Subject: drm/i915/overlay: Explicitly pass regs from map to unmap The scoping of the validity of the mapping is thus clarified. Signed-off-by: Chris Wilson Reviewed-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_drv.h | 1 - drivers/gpu/drm/i915/intel_overlay.c | 61 +++++++++++------------------------- 2 files changed, 18 insertions(+), 44 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index 72f72f5..f757fbd 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -161,7 +161,6 @@ struct intel_overlay { /* register access */ u32 flip_addr; struct drm_i915_gem_object *reg_bo; - void *virt_addr; /* flip handling */ uint32_t last_flip_req; int hw_wedged; diff --git a/drivers/gpu/drm/i915/intel_overlay.c b/drivers/gpu/drm/i915/intel_overlay.c index 7055c46..88c2d1f 100644 --- a/drivers/gpu/drm/i915/intel_overlay.c +++ b/drivers/gpu/drm/i915/intel_overlay.c @@ -177,34 +177,22 @@ intel_overlay_map_regs_atomic(struct intel_overlay *overlay, drm_i915_private_t *dev_priv = overlay->dev->dev_private; struct overlay_registers *regs; - /* no recursive mappings */ - BUG_ON(overlay->virt_addr); - - if (OVERLAY_NEEDS_PHYSICAL(overlay->dev)) { + if (OVERLAY_NEEDS_PHYSICAL(overlay->dev)) regs = overlay->reg_bo->phys_obj->handle->vaddr; - } else { + else regs = io_mapping_map_atomic_wc(dev_priv->mm.gtt_mapping, overlay->reg_bo->gtt_offset, slot); - if (!regs) { - DRM_ERROR("failed to map overlay regs in GTT\n"); - return NULL; - } - } - - return overlay->virt_addr = regs; + return regs; } static void intel_overlay_unmap_regs_atomic(struct intel_overlay *overlay, - int slot) + int slot, + struct overlay_registers *regs) { if (!OVERLAY_NEEDS_PHYSICAL(overlay->dev)) - io_mapping_unmap_atomic(overlay->virt_addr, slot); - - overlay->virt_addr = NULL; - - return; + io_mapping_unmap_atomic(regs, slot); } static struct overlay_registers * @@ -213,32 +201,20 @@ intel_overlay_map_regs(struct intel_overlay *overlay) drm_i915_private_t *dev_priv = overlay->dev->dev_private; struct overlay_registers *regs; - /* no recursive mappings */ - BUG_ON(overlay->virt_addr); - - if (OVERLAY_NEEDS_PHYSICAL(overlay->dev)) { + if (OVERLAY_NEEDS_PHYSICAL(overlay->dev)) regs = overlay->reg_bo->phys_obj->handle->vaddr; - } else { + else regs = io_mapping_map_wc(dev_priv->mm.gtt_mapping, overlay->reg_bo->gtt_offset); - if (!regs) { - DRM_ERROR("failed to map overlay regs in GTT\n"); - return NULL; - } - } - - return overlay->virt_addr = regs; + return regs; } -static void intel_overlay_unmap_regs(struct intel_overlay *overlay) +static void intel_overlay_unmap_regs(struct intel_overlay *overlay, + struct overlay_registers *regs) { if (!OVERLAY_NEEDS_PHYSICAL(overlay->dev)) - io_mapping_unmap(overlay->virt_addr); - - overlay->virt_addr = NULL; - - return; + io_mapping_unmap(regs); } static int intel_overlay_do_wait_request(struct intel_overlay *overlay, @@ -772,7 +748,7 @@ int intel_overlay_do_put_image(struct intel_overlay *overlay, regs->OCONFIG |= OCONF_CSC_MODE_BT709; regs->OCONFIG |= overlay->crtc->pipe == 0 ? OCONF_PIPE_A : OCONF_PIPE_B; - intel_overlay_unmap_regs(overlay); + intel_overlay_unmap_regs(overlay, regs); ret = intel_overlay_on(overlay); if (ret != 0) @@ -822,7 +798,7 @@ int intel_overlay_do_put_image(struct intel_overlay *overlay, regs->OCMD = overlay_cmd_reg(params); - intel_overlay_unmap_regs(overlay); + intel_overlay_unmap_regs(overlay, regs); intel_overlay_continue(overlay, scale_changed); @@ -860,7 +836,7 @@ int intel_overlay_switch_off(struct intel_overlay *overlay) regs = intel_overlay_map_regs(overlay); regs->OCMD = 0; - intel_overlay_unmap_regs(overlay); + intel_overlay_unmap_regs(overlay, regs); ret = intel_overlay_off(overlay); if (ret != 0) @@ -1309,7 +1285,7 @@ int intel_overlay_attrs(struct drm_device *dev, void *data, update_reg_attrs(overlay, regs); - intel_overlay_unmap_regs(overlay); + intel_overlay_unmap_regs(overlay, regs); if (attrs->flags & I915_OVERLAY_UPDATE_GAMMA) { if (!IS_I9XX(dev)) @@ -1398,10 +1374,9 @@ void intel_setup_overlay(struct drm_device *dev) memset(regs, 0, sizeof(struct overlay_registers)); update_polyphase_filter(regs); - update_reg_attrs(overlay, regs); - intel_overlay_unmap_regs(overlay); + intel_overlay_unmap_regs(overlay, regs); dev_priv->overlay = overlay; DRM_INFO("initialized overlay support\n"); @@ -1466,7 +1441,7 @@ intel_overlay_capture_error_state(struct drm_device *dev) goto err; memcpy_fromio(&error->regs, regs, sizeof(struct overlay_registers)); - intel_overlay_unmap_regs_atomic(overlay, KM_IRQ0); + intel_overlay_unmap_regs_atomic(overlay, KM_IRQ0, regs); return error; -- cgit v1.1 From 8dfbc3403113bcc51f0350c3471fa1abf664305f Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Thu, 12 Aug 2010 12:07:32 +0100 Subject: drm/i915/overlay: Combine SWITCH_OFF into a single step We can program the h/w to first wait on the flip and then switch off without relying on s/w intervention. This removes the need for a double step switch off, bringing much rejoicing. Signed-off-by: Chris Wilson Reviewed-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_drv.h | 3 +-- drivers/gpu/drm/i915/intel_overlay.c | 38 +++++------------------------------- 2 files changed, 6 insertions(+), 35 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index f757fbd..01ca494 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -167,8 +167,7 @@ struct intel_overlay { #define HW_WEDGED 1 #define NEEDS_WAIT_FOR_FLIP 2 #define RELEASE_OLD_VID 3 -#define SWITCH_OFF_STAGE_1 4 -#define SWITCH_OFF_STAGE_2 5 +#define SWITCH_OFF 4 }; struct intel_crtc { diff --git a/drivers/gpu/drm/i915/intel_overlay.c b/drivers/gpu/drm/i915/intel_overlay.c index 88c2d1f..d0f901e 100644 --- a/drivers/gpu/drm/i915/intel_overlay.c +++ b/drivers/gpu/drm/i915/intel_overlay.c @@ -325,7 +325,6 @@ static int intel_overlay_off(struct intel_overlay *overlay) { u32 flip_addr = overlay->flip_addr; struct drm_device *dev = overlay->dev; - int ret; BUG_ON(!overlay->active); @@ -335,29 +334,18 @@ static int intel_overlay_off(struct intel_overlay *overlay) * of the hw. Do it in both cases */ flip_addr |= OFC_UPDATE; + BEGIN_LP_RING(6); /* wait for overlay to go idle */ - BEGIN_LP_RING(4); OUT_RING(MI_OVERLAY_FLIP | MI_OVERLAY_CONTINUE); OUT_RING(flip_addr); OUT_RING(MI_WAIT_FOR_EVENT | MI_WAIT_FOR_OVERLAY_FLIP); - OUT_RING(MI_NOOP); - ADVANCE_LP_RING(); - - ret = intel_overlay_do_wait_request(overlay, true, - SWITCH_OFF_STAGE_1); - if (ret) - return ret; - /* turn overlay off */ - BEGIN_LP_RING(4); OUT_RING(MI_OVERLAY_FLIP | MI_OVERLAY_OFF); OUT_RING(flip_addr); OUT_RING(MI_WAIT_FOR_EVENT | MI_WAIT_FOR_OVERLAY_FLIP); - OUT_RING(MI_NOOP); ADVANCE_LP_RING(); - return intel_overlay_do_wait_request(overlay, true, - SWITCH_OFF_STAGE_2); + return intel_overlay_do_wait_request(overlay, true, SWITCH_OFF); } static void intel_overlay_off_tail(struct intel_overlay *overlay) @@ -383,9 +371,8 @@ int intel_overlay_recover_from_interrupt(struct intel_overlay *overlay, bool interruptible) { struct drm_device *dev = overlay->dev; - struct drm_gem_object *obj; drm_i915_private_t *dev_priv = dev->dev_private; - u32 flip_addr; + struct drm_gem_object *obj; int ret; if (overlay->hw_wedged == HW_WEDGED) @@ -404,25 +391,10 @@ int intel_overlay_recover_from_interrupt(struct intel_overlay *overlay, overlay->old_vid_bo = NULL; break; - case SWITCH_OFF_STAGE_1: - flip_addr = overlay->flip_addr; - flip_addr |= OFC_UPDATE; - - BEGIN_LP_RING(4); - OUT_RING(MI_OVERLAY_FLIP | MI_OVERLAY_OFF); - OUT_RING(flip_addr); - OUT_RING(MI_WAIT_FOR_EVENT | MI_WAIT_FOR_OVERLAY_FLIP); - OUT_RING(MI_NOOP); - ADVANCE_LP_RING(); - - ret = intel_overlay_do_wait_request(overlay, interruptible, - SWITCH_OFF_STAGE_2); - if (ret) - return ret; - - case SWITCH_OFF_STAGE_2: + case SWITCH_OFF: intel_overlay_off_tail(overlay); break; + default: BUG_ON(overlay->hw_wedged != NEEDS_WAIT_FOR_FLIP); } -- cgit v1.1 From 5cd68c9864d65e49c910c701716e4e94e09f7ce0 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Thu, 12 Aug 2010 12:21:54 +0100 Subject: drm/i915/overlay: Tidy release_old_vid() Inline the call to wait_flip() and simplify the resulting code. Signed-off-by: Chris Wilson Reviewed-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_overlay.c | 73 ++++++++++++++---------------------- 1 file changed, 28 insertions(+), 45 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_overlay.c b/drivers/gpu/drm/i915/intel_overlay.c index d0f901e..8c660ab 100644 --- a/drivers/gpu/drm/i915/intel_overlay.c +++ b/drivers/gpu/drm/i915/intel_overlay.c @@ -290,36 +290,6 @@ static void intel_overlay_continue(struct intel_overlay *overlay, i915_add_request(dev, NULL, &dev_priv->render_ring); } -static int intel_overlay_wait_flip(struct intel_overlay *overlay) -{ - struct drm_device *dev = overlay->dev; - drm_i915_private_t *dev_priv = dev->dev_private; - int ret; - u32 tmp; - - if (overlay->last_flip_req != 0) { - ret = i915_do_wait_request(dev, - overlay->last_flip_req, true, - &dev_priv->render_ring); - if (ret == 0) { - overlay->last_flip_req = 0; - - tmp = I915_READ(ISR); - - if (!(tmp & I915_OVERLAY_PLANE_FLIP_PENDING_INTERRUPT)) - return 0; - } - } - - /* synchronous slowpath */ - BEGIN_LP_RING(2); - OUT_RING(MI_WAIT_FOR_EVENT | MI_WAIT_FOR_OVERLAY_FLIP); - OUT_RING(MI_NOOP); - ADVANCE_LP_RING(); - - return intel_overlay_do_wait_request(overlay, true, RELEASE_OLD_VID); -} - /* overlay needs to be disabled in OCMD reg */ static int intel_overlay_off(struct intel_overlay *overlay) { @@ -348,6 +318,16 @@ static int intel_overlay_off(struct intel_overlay *overlay) return intel_overlay_do_wait_request(overlay, true, SWITCH_OFF); } +static void intel_overlay_release_old_vid_tail(struct intel_overlay *overlay) +{ + struct drm_gem_object *obj = &overlay->old_vid_bo->base; + + i915_gem_object_unpin(obj); + drm_gem_object_unreference(obj); + + overlay->old_vid_bo = NULL; +} + static void intel_overlay_off_tail(struct intel_overlay *overlay) { struct drm_gem_object *obj; @@ -372,7 +352,6 @@ int intel_overlay_recover_from_interrupt(struct intel_overlay *overlay, { struct drm_device *dev = overlay->dev; drm_i915_private_t *dev_priv = dev->dev_private; - struct drm_gem_object *obj; int ret; if (overlay->hw_wedged == HW_WEDGED) @@ -385,10 +364,7 @@ int intel_overlay_recover_from_interrupt(struct intel_overlay *overlay, switch (overlay->hw_wedged) { case RELEASE_OLD_VID: - obj = &overlay->old_vid_bo->base; - i915_gem_object_unpin(obj); - drm_gem_object_unreference(obj); - overlay->old_vid_bo = NULL; + intel_overlay_release_old_vid_tail(overlay); break; case SWITCH_OFF: @@ -410,23 +386,30 @@ int intel_overlay_recover_from_interrupt(struct intel_overlay *overlay, */ static int intel_overlay_release_old_vid(struct intel_overlay *overlay) { + struct drm_device *dev = overlay->dev; + drm_i915_private_t *dev_priv = dev->dev_private; int ret; - struct drm_gem_object *obj; - /* only wait if there is actually an old frame to release to - * guarantee forward progress */ + /* Only wait if there is actually an old frame to release to + * guarantee forward progress. + */ if (!overlay->old_vid_bo) return 0; - ret = intel_overlay_wait_flip(overlay); - if (ret != 0) - return ret; + if (I915_READ(ISR) & I915_OVERLAY_PLANE_FLIP_PENDING_INTERRUPT) { + /* synchronous slowpath */ + BEGIN_LP_RING(2); + OUT_RING(MI_WAIT_FOR_EVENT | MI_WAIT_FOR_OVERLAY_FLIP); + OUT_RING(MI_NOOP); + ADVANCE_LP_RING(); - obj = &overlay->old_vid_bo->base; - i915_gem_object_unpin(obj); - drm_gem_object_unreference(obj); - overlay->old_vid_bo = NULL; + ret = intel_overlay_do_wait_request(overlay, true, + RELEASE_OLD_VID); + if (ret) + return ret; + } + intel_overlay_release_old_vid_tail(overlay); return 0; } -- cgit v1.1 From 8dc5d14741dc1ee0074a14b360993a10c2c02d24 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Thu, 12 Aug 2010 12:36:12 +0100 Subject: drm/i915: Preallocate requests By allocating the request prior to writing to the ringbuffer, we can abort the operation without leaving the GPU in an inconsistent state. Signed-off-by: Chris Wilson Reviewed-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_drv.h | 5 ++-- drivers/gpu/drm/i915/i915_gem.c | 32 ++++++++++++++++--------- drivers/gpu/drm/i915/intel_overlay.c | 45 ++++++++++++++++++++++++++++-------- 3 files changed, 59 insertions(+), 23 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 10c9e41..1016073 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -992,8 +992,9 @@ int i915_gem_do_init(struct drm_device *dev, unsigned long start, int i915_gpu_idle(struct drm_device *dev); int i915_gem_idle(struct drm_device *dev); uint32_t i915_add_request(struct drm_device *dev, - struct drm_file *file_priv, - struct intel_ring_buffer *ring); + struct drm_file *file_priv, + struct drm_i915_gem_request *request, + struct intel_ring_buffer *ring); int i915_do_wait_request(struct drm_device *dev, uint32_t seqno, bool interruptible, diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index ce66f90..afe4a9b 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -1609,20 +1609,22 @@ i915_gem_process_flushing_list(struct drm_device *dev, uint32_t i915_add_request(struct drm_device *dev, struct drm_file *file_priv, + struct drm_i915_gem_request *request, struct intel_ring_buffer *ring) { drm_i915_private_t *dev_priv = dev->dev_private; struct drm_i915_file_private *i915_file_priv = NULL; - struct drm_i915_gem_request *request; uint32_t seqno; int was_empty; if (file_priv != NULL) i915_file_priv = file_priv->driver_priv; - request = kzalloc(sizeof(*request), GFP_KERNEL); - if (request == NULL) - return 0; + if (request == NULL) { + request = kzalloc(sizeof(*request), GFP_KERNEL); + if (request == NULL) + return 0; + } seqno = ring->add_request(dev, ring, file_priv, 0); @@ -1839,7 +1841,7 @@ i915_do_wait_request(struct drm_device *dev, uint32_t seqno, BUG_ON(seqno == 0); if (seqno == dev_priv->next_seqno) { - seqno = i915_add_request(dev, NULL, ring); + seqno = i915_add_request(dev, NULL, NULL, ring); if (seqno == 0) return -ENOMEM; } @@ -3505,8 +3507,7 @@ i915_gem_wait_for_pending_flip(struct drm_device *dev, return ret; } - -int +static int i915_gem_do_execbuffer(struct drm_device *dev, void *data, struct drm_file *file_priv, struct drm_i915_gem_execbuffer2 *args, @@ -3518,6 +3519,7 @@ i915_gem_do_execbuffer(struct drm_device *dev, void *data, struct drm_i915_gem_object *obj_priv; struct drm_clip_rect *cliprects = NULL; struct drm_i915_gem_relocation_entry *relocs = NULL; + struct drm_i915_gem_request *request = NULL; int ret = 0, ret2, i, pinned = 0; uint64_t exec_offset; uint32_t seqno, reloc_index; @@ -3571,6 +3573,12 @@ i915_gem_do_execbuffer(struct drm_device *dev, void *data, } } + request = kzalloc(sizeof(*request), GFP_KERNEL); + if (request == NULL) { + ret = -ENOMEM; + goto pre_mutex_err; + } + ret = i915_gem_get_relocs_from_user(exec_list, args->buffer_count, &relocs); if (ret != 0) @@ -3736,11 +3744,11 @@ i915_gem_do_execbuffer(struct drm_device *dev, void *data, } if (dev_priv->render_ring.outstanding_lazy_request) { - (void)i915_add_request(dev, file_priv, &dev_priv->render_ring); + (void)i915_add_request(dev, file_priv, NULL, &dev_priv->render_ring); dev_priv->render_ring.outstanding_lazy_request = false; } if (dev_priv->bsd_ring.outstanding_lazy_request) { - (void)i915_add_request(dev, file_priv, &dev_priv->bsd_ring); + (void)i915_add_request(dev, file_priv, NULL, &dev_priv->bsd_ring); dev_priv->bsd_ring.outstanding_lazy_request = false; } @@ -3810,7 +3818,8 @@ i915_gem_do_execbuffer(struct drm_device *dev, void *data, * *some* interrupts representing completion of buffers that we can * wait on when trying to clear up gtt space). */ - seqno = i915_add_request(dev, file_priv, ring); + seqno = i915_add_request(dev, file_priv, request, ring); + request = NULL; #if WATCH_LRU i915_dump_lru(dev, __func__); @@ -3849,6 +3858,7 @@ pre_mutex_err: drm_free_large(object_list); kfree(cliprects); + kfree(request); return ret; } @@ -4199,7 +4209,7 @@ i915_gem_busy_ioctl(struct drm_device *dev, void *data, */ if (obj->write_domain) { i915_gem_flush(dev, 0, obj->write_domain); - (void)i915_add_request(dev, file_priv, obj_priv->ring); + (void)i915_add_request(dev, file_priv, NULL, obj_priv->ring); } /* Update the active list for the hardware's current position. diff --git a/drivers/gpu/drm/i915/intel_overlay.c b/drivers/gpu/drm/i915/intel_overlay.c index 8c660ab..cd0c4bf 100644 --- a/drivers/gpu/drm/i915/intel_overlay.c +++ b/drivers/gpu/drm/i915/intel_overlay.c @@ -218,6 +218,7 @@ static void intel_overlay_unmap_regs(struct intel_overlay *overlay, } static int intel_overlay_do_wait_request(struct intel_overlay *overlay, + struct drm_i915_gem_request *request, bool interruptible, int stage) { @@ -226,7 +227,7 @@ static int intel_overlay_do_wait_request(struct intel_overlay *overlay, int ret; overlay->last_flip_req = - i915_add_request(dev, NULL, &dev_priv->render_ring); + i915_add_request(dev, NULL, request, &dev_priv->render_ring); if (overlay->last_flip_req == 0) return -ENOMEM; @@ -246,11 +247,15 @@ static int intel_overlay_do_wait_request(struct intel_overlay *overlay, static int intel_overlay_on(struct intel_overlay *overlay) { struct drm_device *dev = overlay->dev; + struct drm_i915_gem_request *request; BUG_ON(overlay->active); - overlay->active = 1; + request = kzalloc(sizeof(*request), GFP_KERNEL); + if (request == NULL) + return -ENOMEM; + BEGIN_LP_RING(4); OUT_RING(MI_OVERLAY_FLIP | MI_OVERLAY_ON); OUT_RING(overlay->flip_addr | OFC_UPDATE); @@ -258,21 +263,26 @@ static int intel_overlay_on(struct intel_overlay *overlay) OUT_RING(MI_NOOP); ADVANCE_LP_RING(); - return intel_overlay_do_wait_request(overlay, true, + return intel_overlay_do_wait_request(overlay, request, true, NEEDS_WAIT_FOR_FLIP); } /* overlay needs to be enabled in OCMD reg */ -static void intel_overlay_continue(struct intel_overlay *overlay, - bool load_polyphase_filter) +static int intel_overlay_continue(struct intel_overlay *overlay, + bool load_polyphase_filter) { struct drm_device *dev = overlay->dev; drm_i915_private_t *dev_priv = dev->dev_private; + struct drm_i915_gem_request *request; u32 flip_addr = overlay->flip_addr; u32 tmp; BUG_ON(!overlay->active); + request = kzalloc(sizeof(*request), GFP_KERNEL); + if (request == NULL) + return -ENOMEM; + if (load_polyphase_filter) flip_addr |= OFC_UPDATE; @@ -287,17 +297,23 @@ static void intel_overlay_continue(struct intel_overlay *overlay, ADVANCE_LP_RING(); overlay->last_flip_req = - i915_add_request(dev, NULL, &dev_priv->render_ring); + i915_add_request(dev, NULL, request, &dev_priv->render_ring); + return 0; } /* overlay needs to be disabled in OCMD reg */ static int intel_overlay_off(struct intel_overlay *overlay) { - u32 flip_addr = overlay->flip_addr; struct drm_device *dev = overlay->dev; + u32 flip_addr = overlay->flip_addr; + struct drm_i915_gem_request *request; BUG_ON(!overlay->active); + request = kzalloc(sizeof(*request), GFP_KERNEL); + if (request == NULL) + return -ENOMEM; + /* According to intel docs the overlay hw may hang (when switching * off) without loading the filter coeffs. It is however unclear whether * this applies to the disabling of the overlay or to the switching off @@ -315,7 +331,8 @@ static int intel_overlay_off(struct intel_overlay *overlay) OUT_RING(MI_WAIT_FOR_EVENT | MI_WAIT_FOR_OVERLAY_FLIP); ADVANCE_LP_RING(); - return intel_overlay_do_wait_request(overlay, true, SWITCH_OFF); + return intel_overlay_do_wait_request(overlay, request, true, + SWITCH_OFF); } static void intel_overlay_release_old_vid_tail(struct intel_overlay *overlay) @@ -397,13 +414,19 @@ static int intel_overlay_release_old_vid(struct intel_overlay *overlay) return 0; if (I915_READ(ISR) & I915_OVERLAY_PLANE_FLIP_PENDING_INTERRUPT) { + struct drm_i915_gem_request *request; + /* synchronous slowpath */ + request = kzalloc(sizeof(*request), GFP_KERNEL); + if (request == NULL) + return -ENOMEM; + BEGIN_LP_RING(2); OUT_RING(MI_WAIT_FOR_EVENT | MI_WAIT_FOR_OVERLAY_FLIP); OUT_RING(MI_NOOP); ADVANCE_LP_RING(); - ret = intel_overlay_do_wait_request(overlay, true, + ret = intel_overlay_do_wait_request(overlay, request, true, RELEASE_OLD_VID); if (ret) return ret; @@ -755,7 +778,9 @@ int intel_overlay_do_put_image(struct intel_overlay *overlay, intel_overlay_unmap_regs(overlay, regs); - intel_overlay_continue(overlay, scale_changed); + ret = intel_overlay_continue(overlay, scale_changed); + if (ret) + goto out_unpin; overlay->old_vid_bo = overlay->vid_bo; overlay->vid_bo = to_intel_bo(new_bo); -- cgit v1.1 From 5fe82c5ee1ba2d04183c376038c5d233a0311ec9 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Thu, 12 Aug 2010 12:38:21 +0100 Subject: drm/i915/overlay: Make do_put_image() as static Signed-off-by: Chris Wilson Reviewed-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_overlay.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_overlay.c b/drivers/gpu/drm/i915/intel_overlay.c index cd0c4bf..5ca7ef0 100644 --- a/drivers/gpu/drm/i915/intel_overlay.c +++ b/drivers/gpu/drm/i915/intel_overlay.c @@ -689,9 +689,9 @@ static u32 overlay_cmd_reg(struct put_image_params *params) return cmd; } -int intel_overlay_do_put_image(struct intel_overlay *overlay, - struct drm_gem_object *new_bo, - struct put_image_params *params) +static int intel_overlay_do_put_image(struct intel_overlay *overlay, + struct drm_gem_object *new_bo, + struct put_image_params *params) { int ret, tmp_width; struct overlay_registers *regs; -- cgit v1.1 From 106dadacbeeea92f61a2c32f3651ee31c1b34e31 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Fri, 16 Jul 2010 17:13:01 +0100 Subject: drm/i915/overlay: Workaround i830 overlay activation bug. On i830, there exists a bug where an overlay on pipe B requires the mode clock on pipe A in order to activate. So workaround this by activating pipe A when trying to enable the overlay on pipe B. References: [Bug 29007] GPU hang on video playback with overlay https://bugs.freedesktop.org/show_bug.cgi?id=29007 Signed-off-by: Chris Wilson --- drivers/gpu/drm/i915/intel_overlay.c | 71 ++++++++++++++++++++++++++++++++++-- 1 file changed, 67 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_overlay.c b/drivers/gpu/drm/i915/intel_overlay.c index 5ca7ef0..389690d 100644 --- a/drivers/gpu/drm/i915/intel_overlay.c +++ b/drivers/gpu/drm/i915/intel_overlay.c @@ -243,18 +243,76 @@ static int intel_overlay_do_wait_request(struct intel_overlay *overlay, return 0; } +/* Workaround for i830 bug where pipe a must be enable to change control regs */ +static int +i830_activate_pipe_a(struct drm_device *dev) +{ + drm_i915_private_t *dev_priv = dev->dev_private; + struct intel_crtc *crtc; + struct drm_crtc_helper_funcs *crtc_funcs; + struct drm_display_mode vesa_640x480 = { + DRM_MODE("640x480", DRM_MODE_TYPE_DRIVER, 25175, 640, 656, + 752, 800, 0, 480, 489, 492, 525, 0, + DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) + }, *mode; + + crtc = to_intel_crtc(dev_priv->pipe_to_crtc_mapping[0]); + if (crtc->dpms_mode == DRM_MODE_DPMS_ON) + return 0; + + /* most i8xx have pipe a forced on, so don't trust dpms mode */ + if (I915_READ(PIPEACONF) & PIPEACONF_ENABLE) + return 0; + + crtc_funcs = crtc->base.helper_private; + if (crtc_funcs->dpms == NULL) + return 0; + + DRM_DEBUG_DRIVER("Enabling pipe A in order to enable overlay\n"); + + mode = drm_mode_duplicate(dev, &vesa_640x480); + drm_mode_set_crtcinfo(mode, CRTC_INTERLACE_HALVE_V); + if(!drm_crtc_helper_set_mode(&crtc->base, mode, + crtc->base.x, crtc->base.y, + crtc->base.fb)) + return 0; + + crtc_funcs->dpms(&crtc->base, DRM_MODE_DPMS_ON); + return 1; +} + +static void +i830_deactivate_pipe_a(struct drm_device *dev) +{ + drm_i915_private_t *dev_priv = dev->dev_private; + struct drm_crtc *crtc = dev_priv->pipe_to_crtc_mapping[0]; + struct drm_crtc_helper_funcs *crtc_funcs = crtc->helper_private; + + crtc_funcs->dpms(crtc, DRM_MODE_DPMS_OFF); +} + /* overlay needs to be disable in OCMD reg */ static int intel_overlay_on(struct intel_overlay *overlay) { struct drm_device *dev = overlay->dev; struct drm_i915_gem_request *request; + int pipe_a_quirk = 0; + int ret; BUG_ON(overlay->active); overlay->active = 1; + if (IS_I830(dev)) { + pipe_a_quirk = i830_activate_pipe_a(dev); + if (pipe_a_quirk < 0) + return pipe_a_quirk; + } + request = kzalloc(sizeof(*request), GFP_KERNEL); - if (request == NULL) - return -ENOMEM; + if (request == NULL) { + ret = -ENOMEM; + goto out; + } BEGIN_LP_RING(4); OUT_RING(MI_OVERLAY_FLIP | MI_OVERLAY_ON); @@ -263,8 +321,13 @@ static int intel_overlay_on(struct intel_overlay *overlay) OUT_RING(MI_NOOP); ADVANCE_LP_RING(); - return intel_overlay_do_wait_request(overlay, request, true, - NEEDS_WAIT_FOR_FLIP); + ret = intel_overlay_do_wait_request(overlay, request, true, + NEEDS_WAIT_FOR_FLIP); +out: + if (pipe_a_quirk) + i830_deactivate_pipe_a(dev); + + return ret; } /* overlay needs to be enabled in OCMD reg */ -- cgit v1.1 From 5dcdbcb06badbdf2faa698bf3198e421a1e12840 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Thu, 12 Aug 2010 13:50:28 +0100 Subject: drm/i915/overlay: Pass interruptible to switch_off() During DPMS we currently do not want the overlay code to be interruptible, so pass that information down and only take the uninterrruptible paths. Signed-off-by: Chris Wilson Reviewed-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_display.c | 28 ++++++---------------------- drivers/gpu/drm/i915/intel_drv.h | 5 ++--- drivers/gpu/drm/i915/intel_overlay.c | 23 +++++++++++++---------- 3 files changed, 21 insertions(+), 35 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 120a9c0..e4fb536 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -2223,33 +2223,17 @@ static void ironlake_crtc_dpms(struct drm_crtc *crtc, int mode) static void intel_crtc_dpms_overlay(struct intel_crtc *intel_crtc, bool enable) { - struct intel_overlay *overlay; - int ret; - if (!enable && intel_crtc->overlay) { - overlay = intel_crtc->overlay; - mutex_lock(&overlay->dev->struct_mutex); - for (;;) { - ret = intel_overlay_switch_off(overlay); - if (ret == 0) - break; + struct intel_overlay *overlay = intel_crtc->overlay; - ret = intel_overlay_recover_from_interrupt(overlay, 0); - if (ret != 0) { - /* overlay doesn't react anymore. Usually - * results in a black screen and an unkillable - * X server. */ - BUG(); - overlay->hw_wedged = HW_WEDGED; - break; - } - } + mutex_lock(&overlay->dev->struct_mutex); + (void) intel_overlay_switch_off(overlay, false); mutex_unlock(&overlay->dev->struct_mutex); } - /* Let userspace switch the overlay on again. In most cases userspace - * has to recompute where to put it anyway. */ - return; + /* Let userspace switch the overlay on again. In most cases userspace + * has to recompute where to put it anyway. + */ } static void i9xx_crtc_dpms(struct drm_crtc *crtc, int mode) diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index 01ca494..4474453 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -287,9 +287,8 @@ extern void intel_finish_page_flip_plane(struct drm_device *dev, int plane); extern void intel_setup_overlay(struct drm_device *dev); extern void intel_cleanup_overlay(struct drm_device *dev); -extern int intel_overlay_switch_off(struct intel_overlay *overlay); -extern int intel_overlay_recover_from_interrupt(struct intel_overlay *overlay, - bool interruptible); +extern int intel_overlay_switch_off(struct intel_overlay *overlay, + bool interruptible); extern int intel_overlay_put_image(struct drm_device *dev, void *data, struct drm_file *file_priv); extern int intel_overlay_attrs(struct drm_device *dev, void *data, diff --git a/drivers/gpu/drm/i915/intel_overlay.c b/drivers/gpu/drm/i915/intel_overlay.c index 389690d..3533355 100644 --- a/drivers/gpu/drm/i915/intel_overlay.c +++ b/drivers/gpu/drm/i915/intel_overlay.c @@ -365,7 +365,8 @@ static int intel_overlay_continue(struct intel_overlay *overlay, } /* overlay needs to be disabled in OCMD reg */ -static int intel_overlay_off(struct intel_overlay *overlay) +static int intel_overlay_off(struct intel_overlay *overlay, + bool interruptible) { struct drm_device *dev = overlay->dev; u32 flip_addr = overlay->flip_addr; @@ -394,7 +395,7 @@ static int intel_overlay_off(struct intel_overlay *overlay) OUT_RING(MI_WAIT_FOR_EVENT | MI_WAIT_FOR_OVERLAY_FLIP); ADVANCE_LP_RING(); - return intel_overlay_do_wait_request(overlay, request, true, + return intel_overlay_do_wait_request(overlay, request, interruptible, SWITCH_OFF); } @@ -427,8 +428,8 @@ static void intel_overlay_off_tail(struct intel_overlay *overlay) /* recover from an interruption due to a signal * We have to be careful not to repeat work forever an make forward progess. */ -int intel_overlay_recover_from_interrupt(struct intel_overlay *overlay, - bool interruptible) +static int intel_overlay_recover_from_interrupt(struct intel_overlay *overlay, + bool interruptible) { struct drm_device *dev = overlay->dev; drm_i915_private_t *dev_priv = dev->dev_private; @@ -855,17 +856,19 @@ out_unpin: return ret; } -int intel_overlay_switch_off(struct intel_overlay *overlay) +int intel_overlay_switch_off(struct intel_overlay *overlay, + bool interruptible) { - int ret; struct overlay_registers *regs; struct drm_device *dev = overlay->dev; + int ret; BUG_ON(!mutex_is_locked(&dev->struct_mutex)); BUG_ON(!mutex_is_locked(&dev->mode_config.mutex)); if (overlay->hw_wedged) { - ret = intel_overlay_recover_from_interrupt(overlay, 1); + ret = intel_overlay_recover_from_interrupt(overlay, + interruptible); if (ret != 0) return ret; } @@ -881,7 +884,7 @@ int intel_overlay_switch_off(struct intel_overlay *overlay) regs->OCMD = 0; intel_overlay_unmap_regs(overlay, regs); - ret = intel_overlay_off(overlay); + ret = intel_overlay_off(overlay, interruptible); if (ret != 0) return ret; @@ -1097,7 +1100,7 @@ int intel_overlay_put_image(struct drm_device *dev, void *data, mutex_lock(&dev->mode_config.mutex); mutex_lock(&dev->struct_mutex); - ret = intel_overlay_switch_off(overlay); + ret = intel_overlay_switch_off(overlay, true); mutex_unlock(&dev->struct_mutex); mutex_unlock(&dev->mode_config.mutex); @@ -1135,7 +1138,7 @@ int intel_overlay_put_image(struct drm_device *dev, void *data, if (overlay->crtc != crtc) { struct drm_display_mode *mode = &crtc->base.mode; - ret = intel_overlay_switch_off(overlay); + ret = intel_overlay_switch_off(overlay, true); if (ret != 0) goto out_unlock; -- cgit v1.1 From 23f09ce31ca68af3728ac5eed3e3efb03c5f990a Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Thu, 12 Aug 2010 13:53:37 +0100 Subject: drm/i915/overlay: Make the overlay control struct opaque. Signed-off-by: Chris Wilson Reviewed-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_display.c | 8 ++++---- drivers/gpu/drm/i915/intel_drv.h | 24 ------------------------ drivers/gpu/drm/i915/intel_overlay.c | 23 +++++++++++++++++++++++ 3 files changed, 27 insertions(+), 28 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index e4fb536..0b400d1 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -2224,11 +2224,11 @@ static void ironlake_crtc_dpms(struct drm_crtc *crtc, int mode) static void intel_crtc_dpms_overlay(struct intel_crtc *intel_crtc, bool enable) { if (!enable && intel_crtc->overlay) { - struct intel_overlay *overlay = intel_crtc->overlay; + struct drm_device *dev = intel_crtc->base.dev; - mutex_lock(&overlay->dev->struct_mutex); - (void) intel_overlay_switch_off(overlay, false); - mutex_unlock(&overlay->dev->struct_mutex); + mutex_lock(&dev->struct_mutex); + (void) intel_overlay_switch_off(intel_crtc->overlay, false); + mutex_unlock(&dev->struct_mutex); } /* Let userspace switch the overlay on again. In most cases userspace diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index 4474453..949cfda 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -146,30 +146,6 @@ struct intel_connector { struct drm_connector base; }; -struct intel_crtc; -struct intel_overlay { - struct drm_device *dev; - struct intel_crtc *crtc; - struct drm_i915_gem_object *vid_bo; - struct drm_i915_gem_object *old_vid_bo; - int active; - int pfit_active; - u32 pfit_vscale_ratio; /* shifted-point number, (1<<12) == 1.0 */ - u32 color_key; - u32 brightness, contrast, saturation; - u32 old_xscale, old_yscale; - /* register access */ - u32 flip_addr; - struct drm_i915_gem_object *reg_bo; - /* flip handling */ - uint32_t last_flip_req; - int hw_wedged; -#define HW_WEDGED 1 -#define NEEDS_WAIT_FOR_FLIP 2 -#define RELEASE_OLD_VID 3 -#define SWITCH_OFF 4 -}; - struct intel_crtc { struct drm_crtc base; enum pipe pipe; diff --git a/drivers/gpu/drm/i915/intel_overlay.c b/drivers/gpu/drm/i915/intel_overlay.c index 3533355..0a7d3e6 100644 --- a/drivers/gpu/drm/i915/intel_overlay.c +++ b/drivers/gpu/drm/i915/intel_overlay.c @@ -170,6 +170,29 @@ struct overlay_registers { u16 RESERVEDG[0x100 / 2 - N_HORIZ_UV_TAPS * N_PHASES]; }; +struct intel_overlay { + struct drm_device *dev; + struct intel_crtc *crtc; + struct drm_i915_gem_object *vid_bo; + struct drm_i915_gem_object *old_vid_bo; + int active; + int pfit_active; + u32 pfit_vscale_ratio; /* shifted-point number, (1<<12) == 1.0 */ + u32 color_key; + u32 brightness, contrast, saturation; + u32 old_xscale, old_yscale; + /* register access */ + u32 flip_addr; + struct drm_i915_gem_object *reg_bo; + /* flip handling */ + uint32_t last_flip_req; + int hw_wedged; +#define HW_WEDGED 1 +#define NEEDS_WAIT_FOR_FLIP 2 +#define RELEASE_OLD_VID 3 +#define SWITCH_OFF 4 +}; + static struct overlay_registers * intel_overlay_map_regs_atomic(struct intel_overlay *overlay, int slot) -- cgit v1.1 From b303cf9542b016e2af3b9d17255a7f93cd790ef5 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Thu, 12 Aug 2010 14:03:48 +0100 Subject: drm/i915/overlay: Use a continuation hook to finish work after a flip. Slightly easier to follow than the state machine and now possible as the control structure is opaque and hw_wedged is no longer interferred with. Signed-off-by: Chris Wilson Reviewed-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_overlay.c | 110 ++++++++++++++--------------------- 1 file changed, 44 insertions(+), 66 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_overlay.c b/drivers/gpu/drm/i915/intel_overlay.c index 0a7d3e6..bb2256f 100644 --- a/drivers/gpu/drm/i915/intel_overlay.c +++ b/drivers/gpu/drm/i915/intel_overlay.c @@ -186,11 +186,7 @@ struct intel_overlay { struct drm_i915_gem_object *reg_bo; /* flip handling */ uint32_t last_flip_req; - int hw_wedged; -#define HW_WEDGED 1 -#define NEEDS_WAIT_FOR_FLIP 2 -#define RELEASE_OLD_VID 3 -#define SWITCH_OFF 4 + void (*flip_tail)(struct intel_overlay *); }; static struct overlay_registers * @@ -243,25 +239,25 @@ static void intel_overlay_unmap_regs(struct intel_overlay *overlay, static int intel_overlay_do_wait_request(struct intel_overlay *overlay, struct drm_i915_gem_request *request, bool interruptible, - int stage) + void (*tail)(struct intel_overlay *)) { struct drm_device *dev = overlay->dev; drm_i915_private_t *dev_priv = dev->dev_private; int ret; + BUG_ON(overlay->last_flip_req); overlay->last_flip_req = i915_add_request(dev, NULL, request, &dev_priv->render_ring); if (overlay->last_flip_req == 0) return -ENOMEM; - overlay->hw_wedged = stage; + overlay->flip_tail = tail; ret = i915_do_wait_request(dev, overlay->last_flip_req, true, &dev_priv->render_ring); if (ret) return ret; - overlay->hw_wedged = 0; overlay->last_flip_req = 0; return 0; } @@ -344,8 +340,7 @@ static int intel_overlay_on(struct intel_overlay *overlay) OUT_RING(MI_NOOP); ADVANCE_LP_RING(); - ret = intel_overlay_do_wait_request(overlay, request, true, - NEEDS_WAIT_FOR_FLIP); + ret = intel_overlay_do_wait_request(overlay, request, true, NULL); out: if (pipe_a_quirk) i830_deactivate_pipe_a(dev); @@ -387,6 +382,33 @@ static int intel_overlay_continue(struct intel_overlay *overlay, return 0; } +static void intel_overlay_release_old_vid_tail(struct intel_overlay *overlay) +{ + struct drm_gem_object *obj = &overlay->old_vid_bo->base; + + i915_gem_object_unpin(obj); + drm_gem_object_unreference(obj); + + overlay->old_vid_bo = NULL; +} + +static void intel_overlay_off_tail(struct intel_overlay *overlay) +{ + struct drm_gem_object *obj; + + /* never have the overlay hw on without showing a frame */ + BUG_ON(!overlay->vid_bo); + obj = &overlay->vid_bo->base; + + i915_gem_object_unpin(obj); + drm_gem_object_unreference(obj); + overlay->vid_bo = NULL; + + overlay->crtc->overlay = NULL; + overlay->crtc = NULL; + overlay->active = 0; +} + /* overlay needs to be disabled in OCMD reg */ static int intel_overlay_off(struct intel_overlay *overlay, bool interruptible) @@ -419,34 +441,7 @@ static int intel_overlay_off(struct intel_overlay *overlay, ADVANCE_LP_RING(); return intel_overlay_do_wait_request(overlay, request, interruptible, - SWITCH_OFF); -} - -static void intel_overlay_release_old_vid_tail(struct intel_overlay *overlay) -{ - struct drm_gem_object *obj = &overlay->old_vid_bo->base; - - i915_gem_object_unpin(obj); - drm_gem_object_unreference(obj); - - overlay->old_vid_bo = NULL; -} - -static void intel_overlay_off_tail(struct intel_overlay *overlay) -{ - struct drm_gem_object *obj; - - /* never have the overlay hw on without showing a frame */ - BUG_ON(!overlay->vid_bo); - obj = &overlay->vid_bo->base; - - i915_gem_object_unpin(obj); - drm_gem_object_unreference(obj); - overlay->vid_bo = NULL; - - overlay->crtc->overlay = NULL; - overlay->crtc = NULL; - overlay->active = 0; + intel_overlay_off_tail); } /* recover from an interruption due to a signal @@ -458,28 +453,17 @@ static int intel_overlay_recover_from_interrupt(struct intel_overlay *overlay, drm_i915_private_t *dev_priv = dev->dev_private; int ret; - if (overlay->hw_wedged == HW_WEDGED) - return -EIO; + if (overlay->last_flip_req == 0) + return 0; ret = i915_do_wait_request(dev, overlay->last_flip_req, interruptible, &dev_priv->render_ring); if (ret) return ret; - switch (overlay->hw_wedged) { - case RELEASE_OLD_VID: - intel_overlay_release_old_vid_tail(overlay); - break; + if (overlay->flip_tail) + overlay->flip_tail(overlay); - case SWITCH_OFF: - intel_overlay_off_tail(overlay); - break; - - default: - BUG_ON(overlay->hw_wedged != NEEDS_WAIT_FOR_FLIP); - } - - overlay->hw_wedged = 0; overlay->last_flip_req = 0; return 0; } @@ -514,7 +498,7 @@ static int intel_overlay_release_old_vid(struct intel_overlay *overlay) ADVANCE_LP_RING(); ret = intel_overlay_do_wait_request(overlay, request, true, - RELEASE_OLD_VID); + intel_overlay_release_old_vid_tail); if (ret) return ret; } @@ -889,12 +873,9 @@ int intel_overlay_switch_off(struct intel_overlay *overlay, BUG_ON(!mutex_is_locked(&dev->struct_mutex)); BUG_ON(!mutex_is_locked(&dev->mode_config.mutex)); - if (overlay->hw_wedged) { - ret = intel_overlay_recover_from_interrupt(overlay, - interruptible); - if (ret != 0) - return ret; - } + ret = intel_overlay_recover_from_interrupt(overlay, interruptible); + if (ret != 0) + return ret; if (!overlay->active) return 0; @@ -912,7 +893,6 @@ int intel_overlay_switch_off(struct intel_overlay *overlay, return ret; intel_overlay_off_tail(overlay); - return 0; } @@ -1153,11 +1133,9 @@ int intel_overlay_put_image(struct drm_device *dev, void *data, mutex_lock(&dev->mode_config.mutex); mutex_lock(&dev->struct_mutex); - if (overlay->hw_wedged) { - ret = intel_overlay_recover_from_interrupt(overlay, 1); - if (ret != 0) - goto out_unlock; - } + ret = intel_overlay_recover_from_interrupt(overlay, true); + if (ret != 0) + goto out_unlock; if (overlay->crtc != crtc) { struct drm_display_mode *mode = &crtc->base.mode; -- cgit v1.1 From 3bd3c9329973a93fa3ef5e9840f2fd6fa2889e3f Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Thu, 19 Aug 2010 08:19:30 +0100 Subject: drm/i915: Compile out error state without DEBUG_FS Alexander reported that the compilation of intel_overlay.c was failing due to an inclusion that was only valid with CONFIG_DEBUG_FS. As the whole error reporting is only useful with debugfs enabled, remove all the redundant error state collection code when compiling without CONFIG_DEBUG_FS. Reported-by: Alexander Lam Signed-off-by: Chris Wilson --- drivers/gpu/drm/i915/i915_drv.h | 9 +++++- drivers/gpu/drm/i915/i915_irq.c | 4 +++ drivers/gpu/drm/i915/intel_overlay.c | 55 ++++++++++++++++++++---------------- 3 files changed, 42 insertions(+), 26 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 1016073..634e1c46 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -874,7 +874,6 @@ extern void i915_update_gfx_val(struct drm_i915_private *dev_priv); /* i915_irq.c */ void i915_hangcheck_elapsed(unsigned long data); -void i915_destroy_error_state(struct drm_device *dev); extern int i915_irq_emit(struct drm_device *dev, void *data, struct drm_file *file_priv); extern int i915_irq_wait(struct drm_device *dev, void *data, @@ -911,6 +910,12 @@ i915_disable_pipestat(drm_i915_private_t *dev_priv, int pipe, u32 mask); void intel_enable_asle (struct drm_device *dev); +#ifdef CONFIG_DEBUG_FS +extern void i915_destroy_error_state(struct drm_device *dev); +#else +#define i915_destroy_error_state(x) +#endif + /* i915_mem.c */ extern int i915_mem_alloc(struct drm_device *dev, void *data, @@ -1091,8 +1096,10 @@ extern void intel_detect_pch (struct drm_device *dev); extern int intel_trans_dp_port_sel (struct drm_crtc *crtc); /* overlay */ +#ifdef CONFIG_DEBUG_FS extern struct intel_overlay_error_state *intel_overlay_capture_error_state(struct drm_device *dev); extern void intel_overlay_print_error_state(struct seq_file *m, struct intel_overlay_error_state *error); +#endif /** * Lock test for when it's just for synchronization of ring access. diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c index e797157..080ea3b 100644 --- a/drivers/gpu/drm/i915/i915_irq.c +++ b/drivers/gpu/drm/i915/i915_irq.c @@ -421,6 +421,7 @@ static void i915_error_work_func(struct work_struct *work) } } +#ifdef CONFIG_DEBUG_FS static struct drm_i915_error_object * i915_error_object_create(struct drm_device *dev, struct drm_gem_object *src) @@ -744,6 +745,9 @@ void i915_destroy_error_state(struct drm_device *dev) if (error) i915_error_state_free(dev, error); } +#else +#define i915_capture_error_state(x) +#endif static void i915_report_and_clear_eir(struct drm_device *dev) { diff --git a/drivers/gpu/drm/i915/intel_overlay.c b/drivers/gpu/drm/i915/intel_overlay.c index bb2256f..743ced7 100644 --- a/drivers/gpu/drm/i915/intel_overlay.c +++ b/drivers/gpu/drm/i915/intel_overlay.c @@ -190,31 +190,6 @@ struct intel_overlay { }; static struct overlay_registers * -intel_overlay_map_regs_atomic(struct intel_overlay *overlay, - int slot) -{ - drm_i915_private_t *dev_priv = overlay->dev->dev_private; - struct overlay_registers *regs; - - if (OVERLAY_NEEDS_PHYSICAL(overlay->dev)) - regs = overlay->reg_bo->phys_obj->handle->vaddr; - else - regs = io_mapping_map_atomic_wc(dev_priv->mm.gtt_mapping, - overlay->reg_bo->gtt_offset, - slot); - - return regs; -} - -static void intel_overlay_unmap_regs_atomic(struct intel_overlay *overlay, - int slot, - struct overlay_registers *regs) -{ - if (!OVERLAY_NEEDS_PHYSICAL(overlay->dev)) - io_mapping_unmap_atomic(regs, slot); -} - -static struct overlay_registers * intel_overlay_map_regs(struct intel_overlay *overlay) { drm_i915_private_t *dev_priv = overlay->dev->dev_private; @@ -1454,6 +1429,9 @@ void intel_cleanup_overlay(struct drm_device *dev) kfree(dev_priv->overlay); } +#ifdef CONFIG_DEBUG_FS +#include + struct intel_overlay_error_state { struct overlay_registers regs; unsigned long base; @@ -1461,6 +1439,32 @@ struct intel_overlay_error_state { u32 isr; }; +static struct overlay_registers * +intel_overlay_map_regs_atomic(struct intel_overlay *overlay, + int slot) +{ + drm_i915_private_t *dev_priv = overlay->dev->dev_private; + struct overlay_registers *regs; + + if (OVERLAY_NEEDS_PHYSICAL(overlay->dev)) + regs = overlay->reg_bo->phys_obj->handle->vaddr; + else + regs = io_mapping_map_atomic_wc(dev_priv->mm.gtt_mapping, + overlay->reg_bo->gtt_offset, + slot); + + return regs; +} + +static void intel_overlay_unmap_regs_atomic(struct intel_overlay *overlay, + int slot, + struct overlay_registers *regs) +{ + if (!OVERLAY_NEEDS_PHYSICAL(overlay->dev)) + io_mapping_unmap_atomic(regs, slot); +} + + struct intel_overlay_error_state * intel_overlay_capture_error_state(struct drm_device *dev) { @@ -1549,3 +1553,4 @@ intel_overlay_print_error_state(struct seq_file *m, struct intel_overlay_error_s P(UVSCALEV); #undef P } +#endif -- cgit v1.1 From 015b9c8ce50e5bfb7ea78613dcad4b30d1a0d9da Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Fri, 20 Aug 2010 11:26:59 +0100 Subject: drm/i915: Remove the random SyncFlush during initialisation We have no idea why we request a SyncFlush via INSTPM at that point in time -- we certainly never check for its completion... Signed-off-by: Chris Wilson --- drivers/gpu/drm/i915/i915_dma.c | 6 ------ 1 file changed, 6 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_dma.c b/drivers/gpu/drm/i915/i915_dma.c index 2dae3be9..315326d 100644 --- a/drivers/gpu/drm/i915/i915_dma.c +++ b/drivers/gpu/drm/i915/i915_dma.c @@ -1444,12 +1444,6 @@ static int i915_load_modeset_init(struct drm_device *dev, /* FIXME: do pre/post-mode set stuff in core KMS code */ dev->vblank_disable_allowed = 1; - /* - * Initialize the hardware status page IRQ location. - */ - - I915_WRITE(INSTPM, (1 << 5) | (1 << 21)); - ret = intel_fbdev_init(dev); if (ret) goto cleanup_irq; -- cgit v1.1 From de227ef0907258359d53e3e1530c1f3678eb2bb9 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Sat, 3 Jul 2010 07:58:38 +0100 Subject: drm/i915: Kill the active list spinlock This spinlock only served debugging purposes in a time when we could not be sure of the mutex ever being released upon a GPU hang. As we now should be able rely on hangcheck to do the job for us (and that error reporting should not itself require the struct mutex) we can kill the incomplete attempt at protection. Signed-off-by: Chris Wilson --- drivers/gpu/drm/i915/i915_debugfs.c | 89 +++++++++++++++++++++++++---------- drivers/gpu/drm/i915/i915_drv.h | 2 - drivers/gpu/drm/i915/i915_gem.c | 35 +------------- drivers/gpu/drm/i915/i915_gem_evict.c | 5 -- 4 files changed, 65 insertions(+), 66 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_debugfs.c b/drivers/gpu/drm/i915/i915_debugfs.c index 16133f1..9074300 100644 --- a/drivers/gpu/drm/i915/i915_debugfs.c +++ b/drivers/gpu/drm/i915/i915_debugfs.c @@ -72,12 +72,15 @@ static int i915_gem_object_list_info(struct seq_file *m, void *data) struct drm_device *dev = node->minor->dev; drm_i915_private_t *dev_priv = dev->dev_private; struct drm_i915_gem_object *obj_priv; - spinlock_t *lock = NULL; + int ret; + + ret = mutex_lock_interruptible(&dev->struct_mutex); + if (ret) + return ret; switch (list) { case ACTIVE_LIST: seq_printf(m, "Active:\n"); - lock = &dev_priv->mm.active_list_lock; head = &dev_priv->render_ring.active_list; break; case INACTIVE_LIST: @@ -89,14 +92,11 @@ static int i915_gem_object_list_info(struct seq_file *m, void *data) head = &dev_priv->mm.flushing_list; break; default: - DRM_INFO("Ooops, unexpected list\n"); - return 0; + mutex_unlock(&dev->struct_mutex); + return -EINVAL; } - if (lock) - spin_lock(lock); - list_for_each_entry(obj_priv, head, list) - { + list_for_each_entry(obj_priv, head, list) { seq_printf(m, " %p: %s %8zd %08x %08x %d%s%s", &obj_priv->base, get_pin_flag(obj_priv), @@ -117,8 +117,7 @@ static int i915_gem_object_list_info(struct seq_file *m, void *data) seq_printf(m, "\n"); } - if (lock) - spin_unlock(lock); + mutex_unlock(&dev->struct_mutex); return 0; } @@ -176,6 +175,11 @@ static int i915_gem_request_info(struct seq_file *m, void *data) struct drm_device *dev = node->minor->dev; drm_i915_private_t *dev_priv = dev->dev_private; struct drm_i915_gem_request *gem_request; + int ret; + + ret = mutex_lock_interruptible(&dev->struct_mutex); + if (ret) + return ret; seq_printf(m, "Request:\n"); list_for_each_entry(gem_request, &dev_priv->render_ring.request_list, @@ -184,6 +188,8 @@ static int i915_gem_request_info(struct seq_file *m, void *data) gem_request->seqno, (int) (jiffies - gem_request->emitted_jiffies)); } + mutex_unlock(&dev->struct_mutex); + return 0; } @@ -192,6 +198,11 @@ static int i915_gem_seqno_info(struct seq_file *m, void *data) struct drm_info_node *node = (struct drm_info_node *) m->private; struct drm_device *dev = node->minor->dev; drm_i915_private_t *dev_priv = dev->dev_private; + int ret; + + ret = mutex_lock_interruptible(&dev->struct_mutex); + if (ret) + return ret; if (dev_priv->render_ring.status_page.page_addr != NULL) { seq_printf(m, "Current sequence: %d\n", @@ -202,6 +213,9 @@ static int i915_gem_seqno_info(struct seq_file *m, void *data) seq_printf(m, "Waiter sequence: %d\n", dev_priv->mm.waiting_gem_seqno); seq_printf(m, "IRQ sequence: %d\n", dev_priv->mm.irq_gem_seqno); + + mutex_unlock(&dev->struct_mutex); + return 0; } @@ -211,6 +225,11 @@ static int i915_interrupt_info(struct seq_file *m, void *data) struct drm_info_node *node = (struct drm_info_node *) m->private; struct drm_device *dev = node->minor->dev; drm_i915_private_t *dev_priv = dev->dev_private; + int ret; + + ret = mutex_lock_interruptible(&dev->struct_mutex); + if (ret) + return ret; if (!HAS_PCH_SPLIT(dev)) { seq_printf(m, "Interrupt enable: %08x\n", @@ -255,6 +274,8 @@ static int i915_interrupt_info(struct seq_file *m, void *data) dev_priv->mm.waiting_gem_seqno); seq_printf(m, "IRQ sequence: %d\n", dev_priv->mm.irq_gem_seqno); + mutex_unlock(&dev->struct_mutex); + return 0; } @@ -263,7 +284,11 @@ static int i915_gem_fence_regs_info(struct seq_file *m, void *data) struct drm_info_node *node = (struct drm_info_node *) m->private; struct drm_device *dev = node->minor->dev; drm_i915_private_t *dev_priv = dev->dev_private; - int i; + int i, ret; + + ret = mutex_lock_interruptible(&dev->struct_mutex); + if (ret) + return ret; seq_printf(m, "Reserved fences = %d\n", dev_priv->fence_reg_start); seq_printf(m, "Total fences = %d\n", dev_priv->num_fence_regs); @@ -289,6 +314,7 @@ static int i915_gem_fence_regs_info(struct seq_file *m, void *data) seq_printf(m, "\n"); } } + mutex_unlock(&dev->struct_mutex); return 0; } @@ -319,10 +345,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_atomic(pages[page], KM_USER0); + mem = kmap(pages[page]); for (i = 0; i < PAGE_SIZE; i += 4) seq_printf(m, "%08x : %08x\n", i, mem[i / 4]); - kunmap_atomic(mem, KM_USER0); + kunmap(pages[page]); } } @@ -335,7 +361,9 @@ static int i915_batchbuffer_info(struct seq_file *m, void *data) struct drm_i915_gem_object *obj_priv; int ret; - spin_lock(&dev_priv->mm.active_list_lock); + ret = mutex_lock_interruptible(&dev->struct_mutex); + if (ret) + return ret; list_for_each_entry(obj_priv, &dev_priv->render_ring.active_list, list) { @@ -343,8 +371,7 @@ static int i915_batchbuffer_info(struct seq_file *m, void *data) if (obj->read_domains & I915_GEM_DOMAIN_COMMAND) { ret = i915_gem_object_get_pages(obj, 0); if (ret) { - DRM_ERROR("Failed to get pages: %d\n", ret); - spin_unlock(&dev_priv->mm.active_list_lock); + mutex_unlock(&dev->struct_mutex); return ret; } @@ -355,7 +382,7 @@ static int i915_batchbuffer_info(struct seq_file *m, void *data) } } - spin_unlock(&dev_priv->mm.active_list_lock); + mutex_unlock(&dev->struct_mutex); return 0; } @@ -365,20 +392,24 @@ static int i915_ringbuffer_data(struct seq_file *m, void *data) struct drm_info_node *node = (struct drm_info_node *) m->private; struct drm_device *dev = node->minor->dev; drm_i915_private_t *dev_priv = dev->dev_private; - u8 *virt; - uint32_t *ptr, off; + int ret; + + ret = mutex_lock_interruptible(&dev->struct_mutex); + if (ret) + return ret; if (!dev_priv->render_ring.gem_object) { seq_printf(m, "No ringbuffer setup\n"); - return 0; - } - - virt = dev_priv->render_ring.virtual_start; + } else { + u8 *virt = dev_priv->render_ring.virtual_start; + uint32_t off; - for (off = 0; off < dev_priv->render_ring.size; off += 4) { - ptr = (uint32_t *)(virt + off); - seq_printf(m, "%08x : %08x\n", off, *ptr); + for (off = 0; off < dev_priv->render_ring.size; off += 4) { + uint32_t *ptr = (uint32_t *)(virt + off); + seq_printf(m, "%08x : %08x\n", off, *ptr); + } } + mutex_unlock(&dev->struct_mutex); return 0; } @@ -694,10 +725,16 @@ static int i915_emon_status(struct seq_file *m, void *unused) struct drm_device *dev = node->minor->dev; drm_i915_private_t *dev_priv = dev->dev_private; unsigned long temp, chipset, gfx; + int ret; + + ret = mutex_lock_interruptible(&dev->struct_mutex); + if (ret) + return ret; temp = i915_mch_val(dev_priv); chipset = i915_chipset_val(dev_priv); gfx = i915_gfx_val(dev_priv); + mutex_unlock(&dev->struct_mutex); seq_printf(m, "GMCH temp: %ld\n", temp); seq_printf(m, "Chipset power: %ld\n", chipset); diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 634e1c46..e6fbeb4 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -524,8 +524,6 @@ typedef struct drm_i915_private { */ struct list_head shrink_list; - spinlock_t active_list_lock; - /** * List of objects which are not in the ringbuffer but which * still have a write_domain which needs to be flushed before diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index afe4a9b..b6e4b60 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -1486,7 +1486,6 @@ i915_gem_object_move_to_active(struct drm_gem_object *obj, struct intel_ring_buffer *ring) { struct drm_device *dev = obj->dev; - drm_i915_private_t *dev_priv = dev->dev_private; struct drm_i915_gem_object *obj_priv = to_intel_bo(obj); uint32_t seqno = i915_gem_next_request_seqno(dev, ring); @@ -1500,9 +1499,7 @@ i915_gem_object_move_to_active(struct drm_gem_object *obj, } /* Move from whatever list we were on to the tail of execution. */ - spin_lock(&dev_priv->mm.active_list_lock); list_move_tail(&obj_priv->list, &ring->active_list); - spin_unlock(&dev_priv->mm.active_list_lock); obj_priv->last_rendering_seqno = seqno; } @@ -1676,14 +1673,11 @@ static void i915_gem_retire_request(struct drm_device *dev, struct drm_i915_gem_request *request) { - drm_i915_private_t *dev_priv = dev->dev_private; - trace_i915_gem_request_retire(dev, request->seqno); /* Move any buffers on the active list that are no longer referenced * by the ringbuffer to the flushing/inactive lists as appropriate. */ - spin_lock(&dev_priv->mm.active_list_lock); while (!list_empty(&request->ring->active_list)) { struct drm_gem_object *obj; struct drm_i915_gem_object *obj_priv; @@ -1698,7 +1692,7 @@ i915_gem_retire_request(struct drm_device *dev, * this seqno. */ if (obj_priv->last_rendering_seqno != request->seqno) - goto out; + return; #if WATCH_LRU DRM_INFO("%s: retire %d moves to inactive list %p\n", @@ -1707,22 +1701,9 @@ i915_gem_retire_request(struct drm_device *dev, if (obj->write_domain != 0) i915_gem_object_move_to_flushing(obj); - else { - /* Take a reference on the object so it won't be - * freed while the spinlock is held. The list - * protection for this spinlock is safe when breaking - * the lock like this since the next thing we do - * is just get the head of the list again. - */ - drm_gem_object_reference(obj); + else i915_gem_object_move_to_inactive(obj); - spin_unlock(&dev_priv->mm.active_list_lock); - drm_gem_object_unreference(obj); - spin_lock(&dev_priv->mm.active_list_lock); - } } -out: - spin_unlock(&dev_priv->mm.active_list_lock); } /** @@ -1972,7 +1953,6 @@ int i915_gem_object_unbind(struct drm_gem_object *obj) { struct drm_device *dev = obj->dev; - drm_i915_private_t *dev_priv = dev->dev_private; struct drm_i915_gem_object *obj_priv = to_intel_bo(obj); int ret = 0; @@ -2027,10 +2007,8 @@ i915_gem_object_unbind(struct drm_gem_object *obj) } /* Remove ourselves from the LRU list if present. */ - spin_lock(&dev_priv->mm.active_list_lock); if (!list_empty(&obj_priv->list)) list_del_init(&obj_priv->list); - spin_unlock(&dev_priv->mm.active_list_lock); if (i915_gem_object_is_purgeable(obj_priv)) i915_gem_object_truncate(obj); @@ -2047,13 +2025,10 @@ i915_gpu_idle(struct drm_device *dev) bool lists_empty; int ret; - spin_lock(&dev_priv->mm.active_list_lock); lists_empty = (list_empty(&dev_priv->mm.flushing_list) && list_empty(&dev_priv->render_ring.active_list) && (!HAS_BSD(dev) || list_empty(&dev_priv->bsd_ring.active_list))); - spin_unlock(&dev_priv->mm.active_list_lock); - if (lists_empty) return 0; @@ -4550,11 +4525,8 @@ i915_gem_entervt_ioctl(struct drm_device *dev, void *data, return ret; } - spin_lock(&dev_priv->mm.active_list_lock); BUG_ON(!list_empty(&dev_priv->render_ring.active_list)); BUG_ON(HAS_BSD(dev) && !list_empty(&dev_priv->bsd_ring.active_list)); - spin_unlock(&dev_priv->mm.active_list_lock); - BUG_ON(!list_empty(&dev_priv->mm.flushing_list)); BUG_ON(!list_empty(&dev_priv->mm.inactive_list)); BUG_ON(!list_empty(&dev_priv->render_ring.request_list)); @@ -4606,7 +4578,6 @@ i915_gem_load(struct drm_device *dev) int i; drm_i915_private_t *dev_priv = dev->dev_private; - spin_lock_init(&dev_priv->mm.active_list_lock); INIT_LIST_HEAD(&dev_priv->mm.flushing_list); INIT_LIST_HEAD(&dev_priv->mm.gpu_write_list); INIT_LIST_HEAD(&dev_priv->mm.inactive_list); @@ -4862,12 +4833,10 @@ i915_gpu_is_active(struct drm_device *dev) drm_i915_private_t *dev_priv = dev->dev_private; int lists_empty; - spin_lock(&dev_priv->mm.active_list_lock); lists_empty = list_empty(&dev_priv->mm.flushing_list) && list_empty(&dev_priv->render_ring.active_list); if (HAS_BSD(dev)) lists_empty &= list_empty(&dev_priv->bsd_ring.active_list); - spin_unlock(&dev_priv->mm.active_list_lock); return !lists_empty; } diff --git a/drivers/gpu/drm/i915/i915_gem_evict.c b/drivers/gpu/drm/i915/i915_gem_evict.c index 72cae3c..82430e2 100644 --- a/drivers/gpu/drm/i915/i915_gem_evict.c +++ b/drivers/gpu/drm/i915/i915_gem_evict.c @@ -212,14 +212,11 @@ i915_gem_evict_everything(struct drm_device *dev) int ret; bool lists_empty; - spin_lock(&dev_priv->mm.active_list_lock); lists_empty = (list_empty(&dev_priv->mm.inactive_list) && list_empty(&dev_priv->mm.flushing_list) && list_empty(&dev_priv->render_ring.active_list) && (!HAS_BSD(dev) || list_empty(&dev_priv->bsd_ring.active_list))); - spin_unlock(&dev_priv->mm.active_list_lock); - if (lists_empty) return -ENOSPC; @@ -234,13 +231,11 @@ i915_gem_evict_everything(struct drm_device *dev) if (ret) return ret; - spin_lock(&dev_priv->mm.active_list_lock); lists_empty = (list_empty(&dev_priv->mm.inactive_list) && list_empty(&dev_priv->mm.flushing_list) && list_empty(&dev_priv->render_ring.active_list) && (!HAS_BSD(dev) || list_empty(&dev_priv->bsd_ring.active_list))); - spin_unlock(&dev_priv->mm.active_list_lock); BUG_ON(!lists_empty); return 0; -- cgit v1.1 From 995b6762f0fd54377bbfafdf5328b12de698bfa8 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Fri, 20 Aug 2010 13:23:26 +0100 Subject: drm/i915: Quieten sparse warnings for missing prototypes. Signed-off-by: Chris Wilson --- drivers/gpu/drm/i915/i915_dma.c | 2 +- drivers/gpu/drm/i915/i915_gem.c | 6 +++--- drivers/gpu/drm/i915/i915_irq.c | 6 +++--- drivers/gpu/drm/i915/intel_dp.c | 2 +- drivers/gpu/drm/i915/intel_fb.c | 4 ++-- 5 files changed, 10 insertions(+), 10 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_dma.c b/drivers/gpu/drm/i915/i915_dma.c index 315326d..c52e16f 100644 --- a/drivers/gpu/drm/i915/i915_dma.c +++ b/drivers/gpu/drm/i915/i915_dma.c @@ -1902,7 +1902,7 @@ static struct drm_i915_private *i915_mch_dev; * - dev_priv->fmax * - dev_priv->gpu_busy */ -DEFINE_SPINLOCK(mchdev_lock); +static DEFINE_SPINLOCK(mchdev_lock); /** * i915_read_mch_val - return value for IPS use diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index b6e4b60..e0b7ddc 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -4635,8 +4635,8 @@ i915_gem_load(struct drm_device *dev) * Create a physically contiguous memory object for this object * e.g. for cursor + overlay regs */ -int i915_gem_init_phys_object(struct drm_device *dev, - int id, int size, int align) +static int i915_gem_init_phys_object(struct drm_device *dev, + int id, int size, int align) { drm_i915_private_t *dev_priv = dev->dev_private; struct drm_i915_gem_phys_object *phys_obj; @@ -4668,7 +4668,7 @@ kfree_obj: return ret; } -void i915_gem_free_phys_object(struct drm_device *dev, int id) +static void i915_gem_free_phys_object(struct drm_device *dev, int id) { drm_i915_private_t *dev_priv = dev->dev_private; struct drm_i915_gem_phys_object *phys_obj; diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c index 080ea3b..29215b6 100644 --- a/drivers/gpu/drm/i915/i915_irq.c +++ b/drivers/gpu/drm/i915/i915_irq.c @@ -85,7 +85,7 @@ ironlake_disable_graphics_irq(drm_i915_private_t *dev_priv, u32 mask) } /* For display hotplug interrupt */ -void +static void ironlake_enable_display_irq(drm_i915_private_t *dev_priv, u32 mask) { if ((dev_priv->irq_mask_reg & mask) != 0) { @@ -305,7 +305,7 @@ static void i915_handle_rps_change(struct drm_device *dev) return; } -irqreturn_t ironlake_irq_handler(struct drm_device *dev) +static irqreturn_t ironlake_irq_handler(struct drm_device *dev) { drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; int ret = IRQ_NONE; @@ -1315,7 +1315,7 @@ int i915_vblank_swap(struct drm_device *dev, void *data, return -EINVAL; } -struct drm_i915_gem_request * +static struct drm_i915_gem_request * i915_get_tail_request(struct drm_device *dev) { drm_i915_private_t *dev_priv = dev->dev_private; diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c index 3449a3b..eb6e676 100644 --- a/drivers/gpu/drm/i915/intel_dp.c +++ b/drivers/gpu/drm/i915/intel_dp.c @@ -1513,7 +1513,7 @@ static const struct drm_encoder_funcs intel_dp_enc_funcs = { .destroy = intel_dp_encoder_destroy, }; -void +static void intel_dp_hot_plug(struct intel_encoder *intel_encoder) { struct intel_dp *intel_dp = container_of(intel_encoder, struct intel_dp, base); diff --git a/drivers/gpu/drm/i915/intel_fb.c b/drivers/gpu/drm/i915/intel_fb.c index 7bdc962..42f8a51 100644 --- a/drivers/gpu/drm/i915/intel_fb.c +++ b/drivers/gpu/drm/i915/intel_fb.c @@ -219,8 +219,8 @@ static struct drm_fb_helper_funcs intel_fb_helper_funcs = { .fb_probe = intel_fb_find_or_create_single, }; -int intel_fbdev_destroy(struct drm_device *dev, - struct intel_fbdev *ifbdev) +static int intel_fbdev_destroy(struct drm_device *dev, + struct intel_fbdev *ifbdev) { struct fb_info *info; struct intel_framebuffer *ifb = &ifbdev->ifb; -- cgit v1.1 From 5d607f9b038ea03f5e5b3064d2f3993f9ea67e1e Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Fri, 20 Aug 2010 22:37:03 +0100 Subject: drm/i915: Remove redundant initialisation of fb_base We do it whilst configuring dev->mode_config, so remove the out-of-place earlier initialisation. Signed-off-by: Chris Wilson --- drivers/gpu/drm/i915/i915_dma.c | 4 ---- 1 file changed, 4 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_dma.c b/drivers/gpu/drm/i915/i915_dma.c index c52e16f..8d52f01 100644 --- a/drivers/gpu/drm/i915/i915_dma.c +++ b/drivers/gpu/drm/i915/i915_dma.c @@ -1369,12 +1369,8 @@ static int i915_load_modeset_init(struct drm_device *dev, unsigned long agp_size) { struct drm_i915_private *dev_priv = dev->dev_private; - int fb_bar = IS_I9XX(dev) ? 2 : 0; int ret = 0; - dev->mode_config.fb_base = pci_resource_start(dev->pdev, fb_bar) & - 0xff000000; - /* Basic memrange allocator for stolen space (aka vram) */ drm_mm_init(&dev_priv->vram, 0, prealloc_size); DRM_INFO("set up %ldM of stolen space\n", prealloc_size / (1024*1024)); -- cgit v1.1 From a95735569312f2ab0c80425e2cd1e5cb0b4e1870 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Sun, 22 Aug 2010 13:18:16 +0100 Subject: drm/i915: Refactor panel backlight controls There were two instances of code to control the panel backlight and neither handled the complete set of device variations. Fixes: Bug 29716 - [GM965] Regression: Backlight resets to minimum when changing resolution https://bugs.freedesktop.org/show_bug.cgi?id=29716 And a bug on one of my PineView boxes which overflowed the backlight value. Incorporates part of a similar patch by Matthew Garrett that exposes a native Intel backlight controller. Signed-off-by: Chris Wilson --- drivers/gpu/drm/i915/i915_drv.h | 2 +- drivers/gpu/drm/i915/intel_drv.h | 5 +- drivers/gpu/drm/i915/intel_lvds.c | 56 ++--------------- drivers/gpu/drm/i915/intel_opregion.c | 61 ++----------------- drivers/gpu/drm/i915/intel_panel.c | 109 ++++++++++++++++++++++++++++++++++ 5 files changed, 125 insertions(+), 108 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index e6fbeb4..cfc8bfd 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -319,7 +319,7 @@ typedef struct drm_i915_private { struct intel_overlay *overlay; /* LVDS info */ - int backlight_duty_cycle; /* restore backlight to this value */ + int backlight_level; /* restore backlight to this value */ bool panel_wants_dither; struct drm_display_mode *panel_fixed_mode; struct drm_display_mode *lfp_lvds_vbt_mode; /* if any */ diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index 949cfda..cdf9c78 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -204,13 +204,16 @@ extern bool intel_pch_has_edp(struct drm_crtc *crtc); extern bool intel_dpd_is_edp(struct drm_device *dev); extern void intel_edp_link_config (struct intel_encoder *, int *, int *); - +/* intel_panel.c */ extern void intel_fixed_panel_mode(struct drm_display_mode *fixed_mode, struct drm_display_mode *adjusted_mode); extern void intel_pch_panel_fitting(struct drm_device *dev, int fitting_mode, struct drm_display_mode *mode, struct drm_display_mode *adjusted_mode); +extern u32 intel_panel_get_max_backlight(struct drm_device *dev); +extern u32 intel_panel_get_backlight(struct drm_device *dev); +extern void intel_panel_set_backlight(struct drm_device *dev, u32 level); extern int intel_panel_fitter_pipe (struct drm_device *dev); extern void intel_crtc_load_lut(struct drm_crtc *crtc); diff --git a/drivers/gpu/drm/i915/intel_lvds.c b/drivers/gpu/drm/i915/intel_lvds.c index 047bd95..8320279 100644 --- a/drivers/gpu/drm/i915/intel_lvds.c +++ b/drivers/gpu/drm/i915/intel_lvds.c @@ -54,43 +54,6 @@ static struct intel_lvds *enc_to_intel_lvds(struct drm_encoder *encoder) } /** - * Sets the backlight level. - * - * \param level backlight level, from 0 to intel_lvds_get_max_backlight(). - */ -static void intel_lvds_set_backlight(struct drm_device *dev, int level) -{ - struct drm_i915_private *dev_priv = dev->dev_private; - u32 blc_pwm_ctl, reg; - - if (HAS_PCH_SPLIT(dev)) - reg = BLC_PWM_CPU_CTL; - else - reg = BLC_PWM_CTL; - - blc_pwm_ctl = I915_READ(reg) & ~BACKLIGHT_DUTY_CYCLE_MASK; - I915_WRITE(reg, (blc_pwm_ctl | - (level << BACKLIGHT_DUTY_CYCLE_SHIFT))); -} - -/** - * Returns the maximum level of the backlight duty cycle field. - */ -static u32 intel_lvds_get_max_backlight(struct drm_device *dev) -{ - struct drm_i915_private *dev_priv = dev->dev_private; - u32 reg; - - if (HAS_PCH_SPLIT(dev)) - reg = BLC_PWM_PCH_CTL2; - else - reg = BLC_PWM_CTL; - - return ((I915_READ(reg) & BACKLIGHT_MODULATION_FREQ_MASK) >> - BACKLIGHT_MODULATION_FREQ_SHIFT) * 2; -} - -/** * Sets the power state for the panel. */ static void intel_lvds_set_power(struct drm_device *dev, bool on) @@ -117,9 +80,9 @@ static void intel_lvds_set_power(struct drm_device *dev, bool on) if (wait_for(I915_READ(status_reg) & PP_ON, 1000)) DRM_ERROR("timed out waiting to enable LVDS pipe"); - intel_lvds_set_backlight(dev, dev_priv->backlight_duty_cycle); + intel_panel_set_backlight(dev, dev_priv->backlight_level); } else { - intel_lvds_set_backlight(dev, 0); + intel_panel_set_backlight(dev, 0); I915_WRITE(ctl_reg, I915_READ(ctl_reg) & ~POWER_TARGET_ON); @@ -386,16 +349,8 @@ static void intel_lvds_prepare(struct drm_encoder *encoder) { struct drm_device *dev = encoder->dev; struct drm_i915_private *dev_priv = dev->dev_private; - u32 reg; - - if (HAS_PCH_SPLIT(dev)) - reg = BLC_PWM_CPU_CTL; - else - reg = BLC_PWM_CTL; - dev_priv->saveBLC_PWM_CTL = I915_READ(reg); - dev_priv->backlight_duty_cycle = (dev_priv->saveBLC_PWM_CTL & - BACKLIGHT_DUTY_CYCLE_MASK); + dev_priv->backlight_level = intel_panel_get_backlight(dev); intel_lvds_set_power(dev, false); } @@ -405,9 +360,8 @@ static void intel_lvds_commit( struct drm_encoder *encoder) struct drm_device *dev = encoder->dev; struct drm_i915_private *dev_priv = dev->dev_private; - if (dev_priv->backlight_duty_cycle == 0) - dev_priv->backlight_duty_cycle = - intel_lvds_get_max_backlight(dev); + if (dev_priv->backlight_level == 0) + dev_priv->backlight_level = intel_panel_get_max_backlight(dev); intel_lvds_set_power(dev, true); } diff --git a/drivers/gpu/drm/i915/intel_opregion.c b/drivers/gpu/drm/i915/intel_opregion.c index 3cb1323..917c7dc 100644 --- a/drivers/gpu/drm/i915/intel_opregion.c +++ b/drivers/gpu/drm/i915/intel_opregion.c @@ -31,9 +31,9 @@ #include "drmP.h" #include "i915_drm.h" #include "i915_drv.h" +#include "intel_drv.h" #define PCI_ASLE 0xe4 -#define PCI_LBPC 0xf4 #define PCI_ASLS 0xfc #define OPREGION_HEADER_OFFSET 0 @@ -147,36 +147,17 @@ static u32 asle_set_backlight(struct drm_device *dev, u32 bclp) { struct drm_i915_private *dev_priv = dev->dev_private; struct opregion_asle *asle = dev_priv->opregion.asle; - u32 blc_pwm_ctl, blc_pwm_ctl2; - u32 max_backlight, level, shift; + u32 max; if (!(bclp & ASLE_BCLP_VALID)) return ASLE_BACKLIGHT_FAILED; bclp &= ASLE_BCLP_MSK; - if (bclp < 0 || bclp > 255) + if (bclp > 255) return ASLE_BACKLIGHT_FAILED; - blc_pwm_ctl = I915_READ(BLC_PWM_CTL); - blc_pwm_ctl2 = I915_READ(BLC_PWM_CTL2); - - if (IS_I965G(dev) && (blc_pwm_ctl2 & BLM_COMBINATION_MODE)) - pci_write_config_dword(dev->pdev, PCI_LBPC, bclp); - else { - if (IS_PINEVIEW(dev)) { - blc_pwm_ctl &= ~(BACKLIGHT_DUTY_CYCLE_MASK - 1); - max_backlight = (blc_pwm_ctl & BACKLIGHT_MODULATION_FREQ_MASK) >> - BACKLIGHT_MODULATION_FREQ_SHIFT; - shift = BACKLIGHT_DUTY_CYCLE_SHIFT + 1; - } else { - blc_pwm_ctl &= ~BACKLIGHT_DUTY_CYCLE_MASK; - max_backlight = ((blc_pwm_ctl & BACKLIGHT_MODULATION_FREQ_MASK) >> - BACKLIGHT_MODULATION_FREQ_SHIFT) * 2; - shift = BACKLIGHT_DUTY_CYCLE_SHIFT; - } - level = (bclp * max_backlight) / 255; - I915_WRITE(BLC_PWM_CTL, blc_pwm_ctl | (level << shift)); - } + max = intel_panel_get_max_backlight(dev); + intel_panel_set_backlight(dev, bclp * max / 255); asle->cblv = (bclp*0x64)/0xff | ASLE_CBLV_VALID; return 0; @@ -243,36 +224,6 @@ void intel_opregion_asle_intr(struct drm_device *dev) asle->aslc = asle_stat; } -static u32 asle_set_backlight_ironlake(struct drm_device *dev, u32 bclp) -{ - struct drm_i915_private *dev_priv = dev->dev_private; - struct opregion_asle *asle = dev_priv->opregion.asle; - u32 cpu_pwm_ctl, pch_pwm_ctl2; - u32 max_backlight, level; - - if (!(bclp & ASLE_BCLP_VALID)) - return ASLE_BACKLIGHT_FAILED; - - bclp &= ASLE_BCLP_MSK; - if (bclp < 0 || bclp > 255) - return ASLE_BACKLIGHT_FAILED; - - cpu_pwm_ctl = I915_READ(BLC_PWM_CPU_CTL); - pch_pwm_ctl2 = I915_READ(BLC_PWM_PCH_CTL2); - /* get the max PWM frequency */ - max_backlight = (pch_pwm_ctl2 >> 16) & BACKLIGHT_DUTY_CYCLE_MASK; - /* calculate the expected PMW frequency */ - level = (bclp * max_backlight) / 255; - /* reserve the high 16 bits */ - cpu_pwm_ctl &= ~(BACKLIGHT_DUTY_CYCLE_MASK); - /* write the updated PWM frequency */ - I915_WRITE(BLC_PWM_CPU_CTL, cpu_pwm_ctl | level); - - asle->cblv = (bclp*0x64)/0xff | ASLE_CBLV_VALID; - - return 0; -} - /* Only present on Ironlake+ */ void intel_opregion_gse_intr(struct drm_device *dev) { @@ -297,7 +248,7 @@ void intel_opregion_gse_intr(struct drm_device *dev) } if (asle_req & ASLE_SET_BACKLIGHT) - asle_stat |= asle_set_backlight_ironlake(dev, asle->bclp); + asle_stat |= asle_set_backlight(dev, asle->bclp); if (asle_req & ASLE_SET_PFIT) { DRM_DEBUG_DRIVER("Pfit is not supported\n"); diff --git a/drivers/gpu/drm/i915/intel_panel.c b/drivers/gpu/drm/i915/intel_panel.c index e7f5299..30abe7a 100644 --- a/drivers/gpu/drm/i915/intel_panel.c +++ b/drivers/gpu/drm/i915/intel_panel.c @@ -30,6 +30,8 @@ #include "intel_drv.h" +#define PCI_LBPC 0xf4 /* legacy/combination backlight modes */ + void intel_fixed_panel_mode(struct drm_display_mode *fixed_mode, struct drm_display_mode *adjusted_mode) @@ -109,3 +111,110 @@ done: dev_priv->pch_pf_pos = (x << 16) | y; dev_priv->pch_pf_size = (width << 16) | height; } + +static int is_backlight_combination_mode(struct drm_device *dev) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + + if (IS_I965G(dev)) + return I915_READ(BLC_PWM_CTL2) & BLM_COMBINATION_MODE; + + if (IS_GEN2(dev)) + return I915_READ(BLC_PWM_CTL) & BLM_LEGACY_MODE; + + return 0; +} + +u32 intel_panel_get_max_backlight(struct drm_device *dev) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + u32 max; + + if (HAS_PCH_SPLIT(dev)) { + max = I915_READ(BLC_PWM_PCH_CTL2) >> 16; + } else { + max = I915_READ(BLC_PWM_CTL); + if (IS_PINEVIEW(dev)) { + max >>= 17; + } else { + max >>= 16; + if (!IS_I965G(dev)) + max &= ~1; + } + + if (is_backlight_combination_mode(dev)) + max *= 0xff; + } + + if (max == 0) { + /* XXX add code here to query mode clock or hardware clock + * and program max PWM appropriately. + */ + DRM_ERROR("fixme: max PWM is zero.\n"); + max = 1; + } + + DRM_DEBUG_DRIVER("max backlight PWM = %d\n", max); + return max; +} + +u32 intel_panel_get_backlight(struct drm_device *dev) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + u32 val; + + if (HAS_PCH_SPLIT(dev)) { + val = I915_READ(BLC_PWM_CPU_CTL) & BACKLIGHT_DUTY_CYCLE_MASK; + } else { + val = I915_READ(BLC_PWM_CTL) & BACKLIGHT_DUTY_CYCLE_MASK; + if (IS_PINEVIEW(dev)) + val >>= 1; + + if (is_backlight_combination_mode(dev)){ + u8 lbpc; + + val &= ~1; + pci_read_config_byte(dev->pdev, PCI_LBPC, &lbpc); + val *= lbpc; + val >>= 1; + } + } + + DRM_DEBUG_DRIVER("get backlight PWM = %d\n", val); + return val; +} + +static void intel_pch_panel_set_backlight(struct drm_device *dev, u32 level) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + u32 val = I915_READ(BLC_PWM_CPU_CTL) & ~BACKLIGHT_DUTY_CYCLE_MASK; + I915_WRITE(BLC_PWM_CPU_CTL, val | level); +} + +void intel_panel_set_backlight(struct drm_device *dev, u32 level) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + u32 tmp; + + DRM_DEBUG_DRIVER("set backlight PWM = %d\n", level); + + if (HAS_PCH_SPLIT(dev)) + return intel_pch_panel_set_backlight(dev, level); + + if (is_backlight_combination_mode(dev)){ + u32 max = intel_panel_get_max_backlight(dev); + u8 lpbc; + + lpbc = level * 0xfe / max + 1; + level /= lpbc; + pci_write_config_byte(dev->pdev, PCI_LBPC, lpbc); + } + + tmp = I915_READ(BLC_PWM_CTL); + if (IS_PINEVIEW(dev)) { + tmp &= ~(BACKLIGHT_DUTY_CYCLE_MASK - 1); + level <<= 1; + } else + tmp &= ~BACKLIGHT_DUTY_CYCLE_MASK; + I915_WRITE(BLC_PWM_CTL, tmp | level); +} -- cgit v1.1 From b7ac36dadafa69214faa75a34844d56bd0c14e89 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Tue, 24 Aug 2010 16:07:16 +0100 Subject: drm/i915/tv: After disabling the pipe, use wait_for_vblank_off() Hopefully this is a contributing factor to the spurious TV detection repoted by Ivan Bulatovic and others. References: Bug 16871 - "TV1 connected" with no tv https://bugzilla.kernel.org/show_bug.cgi?id=16871 Signed-off-by: Chris Wilson Reported-by: Ivan Bulatovic Cc: Jesse Barnes --- drivers/gpu/drm/i915/intel_tv.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/intel_tv.c b/drivers/gpu/drm/i915/intel_tv.c index 4a65342..d406672 100644 --- a/drivers/gpu/drm/i915/intel_tv.c +++ b/drivers/gpu/drm/i915/intel_tv.c @@ -1164,7 +1164,7 @@ intel_tv_mode_set(struct drm_encoder *encoder, struct drm_display_mode *mode, I915_WRITE(pipeconf_reg, pipeconf & ~PIPEACONF_ENABLE); /* Wait for vblank for the disable to take effect. */ - intel_wait_for_vblank(dev, intel_crtc->pipe); + intel_wait_for_vblank_off(dev, intel_crtc->pipe); /* Filter ctl must be set before TV_WIN_SIZE */ I915_WRITE(TV_FILTER_CTL_1, TV_AUTO_SCALE); -- cgit v1.1 From 70d39fe4862c6c69c2582c829ec240e05bf24430 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Wed, 25 Aug 2010 16:03:34 +0100 Subject: drm/i915: Show device capabilities in debugfs Signed-off-by: Chris Wilson --- drivers/gpu/drm/i915/i915_debugfs.c | 41 +++++++++++++++++++++++++++++++++++++ 1 file changed, 41 insertions(+) diff --git a/drivers/gpu/drm/i915/i915_debugfs.c b/drivers/gpu/drm/i915/i915_debugfs.c index 9074300..18fd153 100644 --- a/drivers/gpu/drm/i915/i915_debugfs.c +++ b/drivers/gpu/drm/i915/i915_debugfs.c @@ -44,6 +44,46 @@ #define FLUSHING_LIST 2 #define INACTIVE_LIST 3 +static const char *yesno(int v) +{ + return v ? "yes" : "no"; +} + +static int i915_capabilities(struct seq_file *m, void *data) +{ + struct drm_info_node *node = (struct drm_info_node *) m->private; + struct drm_device *dev = node->minor->dev; + const struct intel_device_info *info = INTEL_INFO(dev); + + seq_printf(m, "gen: %d\n", info->gen); +#define B(x) seq_printf(m, #x ": %s\n", yesno(info->x)) + B(is_mobile); + B(is_i8xx); + B(is_i85x); + B(is_i915g); + B(is_i9xx); + B(is_i945gm); + B(is_i965g); + B(is_i965gm); + B(is_g33); + B(need_gfx_hws); + B(is_g4x); + B(is_pineview); + B(is_broadwater); + B(is_crestline); + B(is_ironlake); + B(has_fbc); + B(has_rc6); + B(has_pipe_cxsr); + B(has_hotplug); + B(cursor_needs_physical); + B(has_overlay); + B(overlay_needs_physical); +#undef B + + return 0; +} + static const char *get_pin_flag(struct drm_i915_gem_object *obj_priv) { if (obj_priv->user_pin_count > 0) @@ -880,6 +920,7 @@ static int i915_wedged_create(struct dentry *root, struct drm_minor *minor) } static struct drm_info_list i915_debugfs_list[] = { + {"i915_capabilities", i915_capabilities, 0, 0}, {"i915_gem_active", i915_gem_object_list_info, 0, (void *) ACTIVE_LIST}, {"i915_gem_flushing", i915_gem_object_list_info, 0, (void *) FLUSHING_LIST}, {"i915_gem_inactive", i915_gem_object_list_info, 0, (void *) INACTIVE_LIST}, -- cgit v1.1 From 37811fcc9188f748407646e1157f3ed24ae181a4 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Wed, 25 Aug 2010 22:45:57 +0100 Subject: drm/i915: Show framebuffer info in debugfs Signed-off-by: Chris Wilson --- drivers/gpu/drm/i915/i915_debugfs.c | 83 +++++++++++++++++++++++++++++-------- drivers/gpu/drm/i915/intel_drv.h | 8 +++- drivers/gpu/drm/i915/intel_fb.c | 7 ---- 3 files changed, 73 insertions(+), 25 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_debugfs.c b/drivers/gpu/drm/i915/i915_debugfs.c index 18fd153..2f3e017 100644 --- a/drivers/gpu/drm/i915/i915_debugfs.c +++ b/drivers/gpu/drm/i915/i915_debugfs.c @@ -104,6 +104,27 @@ static const char *get_tiling_flag(struct drm_i915_gem_object *obj_priv) } } +static void +describe_obj(struct seq_file *m, struct drm_i915_gem_object *obj) +{ + seq_printf(m, "%p: %s%s %8zd %08x %08x %d%s%s", + &obj->base, + get_pin_flag(obj), + get_tiling_flag(obj), + obj->base.size, + obj->base.read_domains, + obj->base.write_domain, + obj->last_rendering_seqno, + obj->dirty ? " dirty" : "", + obj->madv == I915_MADV_DONTNEED ? " purgeable" : ""); + if (obj->base.name) + seq_printf(m, " (name: %d)", obj->base.name); + if (obj->fence_reg != I915_FENCE_REG_NONE) + seq_printf(m, " (fence: %d)", obj->fence_reg); + if (obj->gtt_space != NULL) + seq_printf(m, " (gtt_offset: %08x)", obj->gtt_offset); +} + static int i915_gem_object_list_info(struct seq_file *m, void *data) { struct drm_info_node *node = (struct drm_info_node *) m->private; @@ -137,23 +158,8 @@ static int i915_gem_object_list_info(struct seq_file *m, void *data) } list_for_each_entry(obj_priv, head, list) { - seq_printf(m, " %p: %s %8zd %08x %08x %d%s%s", - &obj_priv->base, - get_pin_flag(obj_priv), - obj_priv->base.size, - obj_priv->base.read_domains, - obj_priv->base.write_domain, - obj_priv->last_rendering_seqno, - obj_priv->dirty ? " dirty" : "", - obj_priv->madv == I915_MADV_DONTNEED ? " purgeable" : ""); - - if (obj_priv->base.name) - seq_printf(m, " (name: %d)", obj_priv->base.name); - if (obj_priv->fence_reg != I915_FENCE_REG_NONE) - seq_printf(m, " (fence: %d)", obj_priv->fence_reg); - if (obj_priv->gtt_space != NULL) - seq_printf(m, " (gtt_offset: %08x)", obj_priv->gtt_offset); - + seq_printf(m, " "); + describe_obj(m, obj_priv); seq_printf(m, "\n"); } @@ -815,6 +821,48 @@ static int i915_opregion(struct seq_file *m, void *unused) return 0; } +static int i915_gem_framebuffer_info(struct seq_file *m, void *data) +{ + struct drm_info_node *node = (struct drm_info_node *) m->private; + struct drm_device *dev = node->minor->dev; + drm_i915_private_t *dev_priv = dev->dev_private; + struct intel_fbdev *ifbdev; + struct intel_framebuffer *fb; + int ret; + + ret = mutex_lock_interruptible(&dev->mode_config.mutex); + if (ret) + return ret; + + ifbdev = dev_priv->fbdev; + fb = to_intel_framebuffer(ifbdev->helper.fb); + + seq_printf(m, "fbcon size: %d x %d, depth %d, %d bpp, obj ", + fb->base.width, + fb->base.height, + fb->base.depth, + fb->base.bits_per_pixel); + describe_obj(m, to_intel_bo(fb->obj)); + seq_printf(m, "\n"); + + list_for_each_entry(fb, &dev->mode_config.fb_list, base.head) { + if (&fb->base == ifbdev->helper.fb) + continue; + + seq_printf(m, "user size: %d x %d, depth %d, %d bpp, obj ", + fb->base.width, + fb->base.height, + fb->base.depth, + fb->base.bits_per_pixel); + describe_obj(m, to_intel_bo(fb->obj)); + seq_printf(m, "\n"); + } + + mutex_unlock(&dev->mode_config.mutex); + + return 0; +} + static int i915_wedged_open(struct inode *inode, struct file *filp) @@ -944,6 +992,7 @@ static struct drm_info_list i915_debugfs_list[] = { {"i915_fbc_status", i915_fbc_status, 0}, {"i915_sr_status", i915_sr_status, 0}, {"i915_opregion", i915_opregion, 0}, + {"i915_gem_framebuffer", i915_gem_framebuffer_info, 0}, }; #define I915_DEBUGFS_ENTRIES ARRAY_SIZE(i915_debugfs_list) diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index cdf9c78..b454d1a 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -30,8 +30,8 @@ #include #include "i915_drv.h" #include "drm_crtc.h" - #include "drm_crtc_helper.h" +#include "drm_fb_helper.h" #define _wait_for(COND, MS, W) ({ \ unsigned long timeout__ = jiffies + msecs_to_jiffies(MS); \ @@ -129,6 +129,12 @@ struct intel_framebuffer { struct drm_gem_object *obj; }; +struct intel_fbdev { + struct drm_fb_helper helper; + struct intel_framebuffer ifb; + struct list_head fbdev_list; + struct drm_display_mode *our_mode; +}; struct intel_encoder { struct drm_encoder enc; diff --git a/drivers/gpu/drm/i915/intel_fb.c b/drivers/gpu/drm/i915/intel_fb.c index 42f8a51..0ee4a8c 100644 --- a/drivers/gpu/drm/i915/intel_fb.c +++ b/drivers/gpu/drm/i915/intel_fb.c @@ -44,13 +44,6 @@ #include "i915_drm.h" #include "i915_drv.h" -struct intel_fbdev { - struct drm_fb_helper helper; - struct intel_framebuffer ifb; - struct list_head fbdev_list; - struct drm_display_mode *our_mode; -}; - static struct fb_ops intelfb_ops = { .owner = THIS_MODULE, .fb_check_var = drm_fb_helper_check_var, -- cgit v1.1 From 4b60e5cb707aa1d44fd01680296a2caf45dd6fae Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Sun, 8 Aug 2010 11:53:53 +0100 Subject: drm/i915: Clear scanline waits after disabling the pipe. If we disable the pipe and the GPU is currently waiting on a scanline WAIT_FOR_EVENT, the GPU will hang. Fortunately, there is a magic bit which we can write on i915+ to break this wait after disabling the pipe. References: Bug 29252 - [Arrandale] Hung WAIT_FOR_EVENT when running rss-glx-skyrocket https://bugs.freedesktop.org/show_bug.cgi?id=29252 Bug 28964 - [i965gm] GPU infinite MI_WAIT_FOR_EVENT while watching video in Totem https://bugs.freedesktop.org/show_bug.cgi?id=28964 and many others. Signed-off-by: Chris Wilson Cc: Jesse Barnes --- drivers/gpu/drm/i915/i915_reg.h | 2 ++ drivers/gpu/drm/i915/intel_display.c | 31 +++++++++++++++++++++++++++++-- 2 files changed, 31 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index e240de9..5ede5a5 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -295,6 +295,8 @@ #define RING_VALID_MASK 0x00000001 #define RING_VALID 0x00000001 #define RING_INVALID 0x00000000 +#define RING_WAIT_I8XX (1<<0) /* gen2, PRBx_HEAD */ +#define RING_WAIT (1<<11) /* gen3+, PRBx_CTL */ #define PRB1_TAIL 0x02040 /* 915+ only */ #define PRB1_HEAD 0x02044 /* 915+ only */ #define PRB1_START 0x02048 /* 915+ only */ diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 0b400d1..d5cb7ba 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -2344,6 +2344,26 @@ static void i9xx_crtc_dpms(struct drm_crtc *crtc, int mode) } } +/* + * When we disable a pipe, we need to clear any pending scanline wait events + * to avoid hanging the ring, which we assume we are waiting on. + */ +static void intel_clear_scanline_wait(struct drm_device *dev) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + u32 tmp; + + if (IS_GEN2(dev)) + /* Can't break the hang on i8xx */ + return; + + tmp = I915_READ(PRB0_CTL); + if (tmp & RING_WAIT) { + I915_WRITE(PRB0_CTL, tmp); + POSTING_READ(PRB0_CTL); + } +} + /** * Sets the power management mode of the pipe and plane. */ @@ -2366,7 +2386,8 @@ static void intel_crtc_dpms(struct drm_crtc *crtc, int mode) * with multiple pipes prior to enabling to new pipe. * * When switching off the display, make sure the cursor is - * properly hidden prior to disabling the pipe. + * properly hidden and there are no pending waits prior to + * disabling the pipe. */ if (mode == DRM_MODE_DPMS_ON) intel_update_watermarks(dev); @@ -2377,8 +2398,14 @@ static void intel_crtc_dpms(struct drm_crtc *crtc, int mode) if (mode == DRM_MODE_DPMS_ON) intel_crtc_update_cursor(crtc); - else + else { + /* XXX Note that this is not a complete solution, but a hack + * to avoid the most frequently hit hang. + */ + intel_clear_scanline_wait(dev); + intel_update_watermarks(dev); + } if (!dev->primary->master) return; -- cgit v1.1 From 8c80b59b370b4d942f595bdb4a6d23494f77a810 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Sun, 8 Aug 2010 20:38:12 +0100 Subject: drm/i915: Add ringbuffer wait reset to hangcheck The GPU records whether it is currently waiting for a completion of a WAIT_FOR_EVENT in the RB_WAIT bit in the ringbuffer control registers. On third generation chipsets and later, a write of 1 to this bit breaks the hang and returns the GPU to arbitration, i.e. the GPU should continue executing the reminder of the batchbuffer and return to normal operations. By adding this to hangcheck we can avoid a full GPU reset under these conditions. Signed-off-by: Chris Wilson --- drivers/gpu/drm/i915/i915_irq.c | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c index 29215b6..2f7f7cb 100644 --- a/drivers/gpu/drm/i915/i915_irq.c +++ b/drivers/gpu/drm/i915/i915_irq.c @@ -1373,6 +1373,21 @@ void i915_hangcheck_elapsed(unsigned long data) dev_priv->last_instdone1 == instdone1) { if (dev_priv->hangcheck_count++ > 1) { DRM_ERROR("Hangcheck timer elapsed... GPU hung\n"); + + if (!IS_GEN2(dev)) { + /* Is the chip hanging on a WAIT_FOR_EVENT? + * If so we can simply poke the RB_WAIT bit + * and break the hang. This should work on + * all but the second generation chipsets. + */ + u32 tmp = I915_READ(PRB0_CTL); + if (tmp & RING_WAIT) { + I915_WRITE(PRB0_CTL, tmp); + POSTING_READ(PRB0_CTL); + goto out; + } + } + i915_handle_error(dev, true); return; } @@ -1384,6 +1399,7 @@ void i915_hangcheck_elapsed(unsigned long data) dev_priv->last_instdone1 = instdone1; } +out: /* Reset timer case chip hangs without another request being added */ mod_timer(&dev_priv->hangcheck_timer, jiffies + DRM_I915_HANGCHECK_PERIOD); } -- cgit v1.1 From dd2575ffbd71d0922eb31b94adc0923f9808c915 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Sat, 4 Sep 2010 12:59:16 +0100 Subject: drm/i915: Remove impossible error handling from bit17 swizzling Our usage of kmap() cannot return NULL here, so remove the unnecessary error handling. Signed-off-by: Chris Wilson --- drivers/gpu/drm/i915/i915_gem_tiling.c | 14 +++----------- 1 file changed, 3 insertions(+), 11 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_gem_tiling.c b/drivers/gpu/drm/i915/i915_gem_tiling.c index 710eca7..3c0859e 100644 --- a/drivers/gpu/drm/i915/i915_gem_tiling.c +++ b/drivers/gpu/drm/i915/i915_gem_tiling.c @@ -399,16 +399,14 @@ i915_gem_get_tiling(struct drm_device *dev, void *data, * bit 17 of its physical address and therefore being interpreted differently * by the GPU. */ -static int +static void i915_gem_swizzle_page(struct page *page) { + char temp[64]; char *vaddr; int i; - char temp[64]; vaddr = kmap(page); - if (vaddr == NULL) - return -ENOMEM; for (i = 0; i < PAGE_SIZE; i += 128) { memcpy(temp, &vaddr[i], 64); @@ -417,8 +415,6 @@ i915_gem_swizzle_page(struct page *page) } kunmap(page); - - return 0; } void @@ -440,11 +436,7 @@ i915_gem_object_do_bit_17_swizzle(struct drm_gem_object *obj) char new_bit_17 = page_to_phys(obj_priv->pages[i]) >> 17; if ((new_bit_17 & 0x1) != (test_bit(i, obj_priv->bit_17) != 0)) { - int ret = i915_gem_swizzle_page(obj_priv->pages[i]); - if (ret != 0) { - DRM_ERROR("Failed to swizzle page\n"); - return; - } + i915_gem_swizzle_page(obj_priv->pages[i]); set_page_dirty(obj_priv->pages[i]); } } -- cgit v1.1 From 4f0d1aff791db8935ee146fe7928b63bba0f1b59 Mon Sep 17 00:00:00 2001 From: Jesse Barnes Date: Tue, 7 Sep 2010 14:48:05 -0700 Subject: drm/i915: fix pipeconf dither bit definitions Make them match the others and add BPP definitions. Signed-off-by: Jesse Barnes Signed-off-by: Chris Wilson --- drivers/gpu/drm/i915/i915_reg.h | 16 +++++++++++----- drivers/gpu/drm/i915/intel_display.c | 8 ++++---- 2 files changed, 15 insertions(+), 9 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index 5ede5a5..d0b4b23 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -2078,11 +2078,6 @@ /* Display & cursor control */ -/* dithering flag on Ironlake */ -#define PIPE_ENABLE_DITHER (1 << 4) -#define PIPE_DITHER_TYPE_MASK (3 << 2) -#define PIPE_DITHER_TYPE_SPATIAL (0 << 2) -#define PIPE_DITHER_TYPE_ST01 (1 << 2) /* Pipe A */ #define PIPEADSL 0x70000 #define DSL_LINEMASK 0x00000fff @@ -2101,6 +2096,17 @@ #define PIPECONF_INTERLACE_W_FIELD_INDICATION (6 << 21) #define PIPECONF_INTERLACE_FIELD_0_ONLY (7 << 21) #define PIPECONF_CXSR_DOWNCLOCK (1<<16) +#define PIPECONF_BPP_MASK (0x000000e0) +#define PIPECONF_BPP_8 (0<<5) +#define PIPECONF_BPP_10 (1<<5) +#define PIPECONF_BPP_6 (2<<5) +#define PIPECONF_BPP_12 (3<<5) +#define PIPECONF_DITHER_EN (1<<4) +#define PIPECONF_DITHER_TYPE_MASK (0x0000000c) +#define PIPECONF_DITHER_TYPE_SP (0<<2) +#define PIPECONF_DITHER_TYPE_ST1 (1<<2) +#define PIPECONF_DITHER_TYPE_ST2 (2<<2) +#define PIPECONF_DITHER_TYPE_TEMP (3<<2) #define PIPEASTAT 0x70024 #define PIPE_FIFO_UNDERRUN_STATUS (1UL<<31) #define PIPE_CRC_ERROR_ENABLE (1UL<<29) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index d5cb7ba..948a3608 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -3910,8 +3910,8 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc, } if (HAS_PCH_SPLIT(dev)) { - pipeconf &= ~PIPE_ENABLE_DITHER; - pipeconf &= ~PIPE_DITHER_TYPE_MASK; + pipeconf &= ~PIPECONF_DITHER_EN; + pipeconf &= ~PIPECONF_DITHER_TYPE_MASK; } /* The LVDS pin pair needs to be on before the DPLLs are enabled. @@ -3955,8 +3955,8 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc, if (IS_I965G(dev)) { if (dev_priv->lvds_dither) { if (HAS_PCH_SPLIT(dev)) { - pipeconf |= PIPE_ENABLE_DITHER; - pipeconf |= PIPE_DITHER_TYPE_ST01; + pipeconf |= PIPECONF_DITHER_EN; + pipeconf |= PIPECONF_DITHER_TYPE_ST1; } else lvds |= LVDS_ENABLE_DITHER; } else { -- cgit v1.1 From 434ed097245423c5ea277d18121c0fad0df42abf Mon Sep 17 00:00:00 2001 From: Jesse Barnes Date: Tue, 7 Sep 2010 14:48:06 -0700 Subject: drm/i915: set dither bits on eDP panels too We really need a macro to test whether a given connector has a panel attached rather than sprinkling HAS_PCH_SPLIT/IS_eDP/has_edp_encoder etc all over. In the meantime, fix the bug... Signed-off-by: Jesse Barnes [ickle: tidy up the duplicity in the conditionals] Signed-off-by: Chris Wilson --- drivers/gpu/drm/i915/intel_display.c | 35 +++++++++++++++++------------------ 1 file changed, 17 insertions(+), 18 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 948a3608..4b23646 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -3909,11 +3909,6 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc, udelay(150); } - if (HAS_PCH_SPLIT(dev)) { - pipeconf &= ~PIPECONF_DITHER_EN; - pipeconf &= ~PIPECONF_DITHER_TYPE_MASK; - } - /* The LVDS pin pair needs to be on before the DPLLs are enabled. * This is an exception to the general rule that mode_set doesn't turn * things on. @@ -3951,23 +3946,27 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc, * appropriately here, but we need to look more thoroughly into how * panels behave in the two modes. */ - /* set the dithering flag */ - if (IS_I965G(dev)) { - if (dev_priv->lvds_dither) { - if (HAS_PCH_SPLIT(dev)) { - pipeconf |= PIPECONF_DITHER_EN; - pipeconf |= PIPECONF_DITHER_TYPE_ST1; - } else - lvds |= LVDS_ENABLE_DITHER; - } else { - if (!HAS_PCH_SPLIT(dev)) { - lvds &= ~LVDS_ENABLE_DITHER; - } - } + /* set the dithering flag on non-PCH LVDS as needed */ + if (IS_I965G(dev) && !HAS_PCH_SPLIT(dev)) { + if (dev_priv->lvds_dither) + lvds |= LVDS_ENABLE_DITHER; + else + lvds &= ~LVDS_ENABLE_DITHER; } I915_WRITE(lvds_reg, lvds); I915_READ(lvds_reg); } + + /* set the dithering flag and clear for anything other than a panel. */ + if (HAS_PCH_SPLIT(dev)) { + pipeconf &= ~PIPECONF_DITHER_EN; + pipeconf &= ~PIPECONF_DITHER_TYPE_MASK; + if (dev_priv->lvds_dither && (is_lvds || has_edp_encoder)) { + pipeconf |= PIPECONF_DITHER_EN; + pipeconf |= PIPECONF_DITHER_TYPE_ST1; + } + } + if (is_dp) intel_dp_set_m_n(crtc, mode, adjusted_mode); else if (HAS_PCH_SPLIT(dev)) { -- cgit v1.1 From 309b1e3ab750c0ad4d77c6a6e434402e3346baf4 Mon Sep 17 00:00:00 2001 From: Matthew Garrett Date: Tue, 18 May 2010 13:53:16 -0400 Subject: drm/i915: Don't disable panel for modesetting if pfit hasn't changed It seems to be possible to program a new mode without disabling the panel if the panel fitter setup doesn't change. Add support for that. Signed-off-by: Matthew Garrett Acked-by: Jesse Barnes Signed-off-by: Chris Wilson --- drivers/gpu/drm/i915/intel_lvds.c | 21 +++++++++++++++++++-- 1 file changed, 19 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_lvds.c b/drivers/gpu/drm/i915/intel_lvds.c index 8320279..ef64551 100644 --- a/drivers/gpu/drm/i915/intel_lvds.c +++ b/drivers/gpu/drm/i915/intel_lvds.c @@ -53,6 +53,16 @@ static struct intel_lvds *enc_to_intel_lvds(struct drm_encoder *encoder) return container_of(enc_to_intel_encoder(encoder), struct intel_lvds, base); } +static void intel_lvds_lock_panel(struct drm_device *dev, bool lock) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + + if (lock) + I915_WRITE(PP_CONTROL, I915_READ(PP_CONTROL) & 0x3); + else + I915_WRITE(PP_CONTROL, I915_READ(PP_CONTROL) | PANEL_UNLOCK_REGS); +} + /** * Sets the power state for the panel. */ @@ -349,10 +359,14 @@ static void intel_lvds_prepare(struct drm_encoder *encoder) { struct drm_device *dev = encoder->dev; struct drm_i915_private *dev_priv = dev->dev_private; + struct intel_lvds *intel_lvds = enc_to_intel_lvds(encoder); dev_priv->backlight_level = intel_panel_get_backlight(dev); - intel_lvds_set_power(dev, false); + if (intel_lvds->pfit_control == I915_READ(PFIT_CONTROL)) + intel_lvds_lock_panel(dev, false); + else + intel_lvds_set_power(dev, false); } static void intel_lvds_commit( struct drm_encoder *encoder) @@ -363,7 +377,10 @@ static void intel_lvds_commit( struct drm_encoder *encoder) if (dev_priv->backlight_level == 0) dev_priv->backlight_level = intel_panel_get_max_backlight(dev); - intel_lvds_set_power(dev, true); + if ((I915_READ(PP_CONTROL) & PANEL_UNLOCK_REGS) == PANEL_UNLOCK_REGS) + intel_lvds_lock_panel(dev, true); + else + intel_lvds_set_power(dev, true); } static void intel_lvds_mode_set(struct drm_encoder *encoder, -- cgit v1.1 From 02c026ced58f33bb5702d3063c05dae2b651e4ba Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Tue, 24 Aug 2010 19:39:48 +0200 Subject: agp/intel: split out gmch/gtt probe, part 2 This just splits the device list into two and moves the gtt related stuff to intel-gtt.c. The two new devices lists also lose the not longer needed fields. There where only about 5 cases anyway with both a gmch and a possible agp port, so the duplication of entries is rather small. Additionally kill 2 out of the three Ironlake mobile entries that only differed in host bridge pci id. Signed-off-by: Daniel Vetter Signed-off-by: Chris Wilson --- drivers/char/agp/intel-agp.c | 195 +++++-------------------------------------- drivers/char/agp/intel-gtt.c | 124 +++++++++++++++++++++++++++ 2 files changed, 147 insertions(+), 172 deletions(-) diff --git a/drivers/char/agp/intel-agp.c b/drivers/char/agp/intel-agp.c index eab58db..c818a4d 100644 --- a/drivers/char/agp/intel-agp.c +++ b/drivers/char/agp/intel-agp.c @@ -703,177 +703,37 @@ static const struct agp_bridge_driver intel_7505_driver = { .agp_type_to_mask_type = agp_generic_type_to_mask_type, }; -static int find_gmch(u16 device) -{ - struct pci_dev *gmch_device; - - gmch_device = pci_get_device(PCI_VENDOR_ID_INTEL, device, NULL); - if (gmch_device && PCI_FUNC(gmch_device->devfn) != 0) { - gmch_device = pci_get_device(PCI_VENDOR_ID_INTEL, - device, gmch_device); - } - - if (!gmch_device) - return 0; - - intel_private.pcidev = gmch_device; - return 1; -} - /* Table to describe Intel GMCH and AGP/PCIE GART drivers. At least one of * driver and gmch_driver must be non-null, and find_gmch will determine * which one should be used if a gmch_chip_id is present. */ -static const struct intel_driver_description { +static const struct intel_agp_driver_description { unsigned int chip_id; - unsigned int gmch_chip_id; char *name; const struct agp_bridge_driver *driver; - const struct agp_bridge_driver *gmch_driver; } intel_agp_chipsets[] = { - { PCI_DEVICE_ID_INTEL_82443LX_0, 0, "440LX", &intel_generic_driver, NULL }, - { PCI_DEVICE_ID_INTEL_82443BX_0, 0, "440BX", &intel_generic_driver, NULL }, - { PCI_DEVICE_ID_INTEL_82443GX_0, 0, "440GX", &intel_generic_driver, NULL }, - { PCI_DEVICE_ID_INTEL_82810_MC1, PCI_DEVICE_ID_INTEL_82810_IG1, "i810", - NULL, &intel_810_driver }, - { PCI_DEVICE_ID_INTEL_82810_MC3, PCI_DEVICE_ID_INTEL_82810_IG3, "i810", - NULL, &intel_810_driver }, - { PCI_DEVICE_ID_INTEL_82810E_MC, PCI_DEVICE_ID_INTEL_82810E_IG, "i810", - NULL, &intel_810_driver }, - { PCI_DEVICE_ID_INTEL_82815_MC, PCI_DEVICE_ID_INTEL_82815_CGC, "i815", - &intel_815_driver, &intel_810_driver }, - { PCI_DEVICE_ID_INTEL_82820_HB, 0, "i820", &intel_820_driver, NULL }, - { PCI_DEVICE_ID_INTEL_82820_UP_HB, 0, "i820", &intel_820_driver, NULL }, - { PCI_DEVICE_ID_INTEL_82830_HB, PCI_DEVICE_ID_INTEL_82830_CGC, "830M", - &intel_830mp_driver, &intel_830_driver }, - { PCI_DEVICE_ID_INTEL_82840_HB, 0, "i840", &intel_840_driver, NULL }, - { PCI_DEVICE_ID_INTEL_82845_HB, 0, "845G", &intel_845_driver, NULL }, - { PCI_DEVICE_ID_INTEL_82845G_HB, PCI_DEVICE_ID_INTEL_82845G_IG, "830M", - &intel_845_driver, &intel_830_driver }, - { PCI_DEVICE_ID_INTEL_82850_HB, 0, "i850", &intel_850_driver, NULL }, - { PCI_DEVICE_ID_INTEL_82854_HB, PCI_DEVICE_ID_INTEL_82854_IG, "854", - &intel_845_driver, &intel_830_driver }, - { PCI_DEVICE_ID_INTEL_82855PM_HB, 0, "855PM", &intel_845_driver, NULL }, - { PCI_DEVICE_ID_INTEL_82855GM_HB, PCI_DEVICE_ID_INTEL_82855GM_IG, "855GM", - &intel_845_driver, &intel_830_driver }, - { PCI_DEVICE_ID_INTEL_82860_HB, 0, "i860", &intel_860_driver, NULL }, - { PCI_DEVICE_ID_INTEL_82865_HB, PCI_DEVICE_ID_INTEL_82865_IG, "865", - &intel_845_driver, &intel_830_driver }, - { PCI_DEVICE_ID_INTEL_82875_HB, 0, "i875", &intel_845_driver, NULL }, - { PCI_DEVICE_ID_INTEL_E7221_HB, PCI_DEVICE_ID_INTEL_E7221_IG, "E7221 (i915)", - NULL, &intel_915_driver }, - { PCI_DEVICE_ID_INTEL_82915G_HB, PCI_DEVICE_ID_INTEL_82915G_IG, "915G", - NULL, &intel_915_driver }, - { PCI_DEVICE_ID_INTEL_82915GM_HB, PCI_DEVICE_ID_INTEL_82915GM_IG, "915GM", - NULL, &intel_915_driver }, - { PCI_DEVICE_ID_INTEL_82945G_HB, PCI_DEVICE_ID_INTEL_82945G_IG, "945G", - NULL, &intel_915_driver }, - { PCI_DEVICE_ID_INTEL_82945GM_HB, PCI_DEVICE_ID_INTEL_82945GM_IG, "945GM", - NULL, &intel_915_driver }, - { PCI_DEVICE_ID_INTEL_82945GME_HB, PCI_DEVICE_ID_INTEL_82945GME_IG, "945GME", - NULL, &intel_915_driver }, - { PCI_DEVICE_ID_INTEL_82946GZ_HB, PCI_DEVICE_ID_INTEL_82946GZ_IG, "946GZ", - NULL, &intel_i965_driver }, - { PCI_DEVICE_ID_INTEL_82G35_HB, PCI_DEVICE_ID_INTEL_82G35_IG, "G35", - NULL, &intel_i965_driver }, - { PCI_DEVICE_ID_INTEL_82965Q_HB, PCI_DEVICE_ID_INTEL_82965Q_IG, "965Q", - NULL, &intel_i965_driver }, - { PCI_DEVICE_ID_INTEL_82965G_HB, PCI_DEVICE_ID_INTEL_82965G_IG, "965G", - NULL, &intel_i965_driver }, - { PCI_DEVICE_ID_INTEL_82965GM_HB, PCI_DEVICE_ID_INTEL_82965GM_IG, "965GM", - NULL, &intel_i965_driver }, - { PCI_DEVICE_ID_INTEL_82965GME_HB, PCI_DEVICE_ID_INTEL_82965GME_IG, "965GME/GLE", - NULL, &intel_i965_driver }, - { PCI_DEVICE_ID_INTEL_7505_0, 0, "E7505", &intel_7505_driver, NULL }, - { PCI_DEVICE_ID_INTEL_7205_0, 0, "E7205", &intel_7505_driver, NULL }, - { PCI_DEVICE_ID_INTEL_G33_HB, PCI_DEVICE_ID_INTEL_G33_IG, "G33", - NULL, &intel_g33_driver }, - { PCI_DEVICE_ID_INTEL_Q35_HB, PCI_DEVICE_ID_INTEL_Q35_IG, "Q35", - NULL, &intel_g33_driver }, - { PCI_DEVICE_ID_INTEL_Q33_HB, PCI_DEVICE_ID_INTEL_Q33_IG, "Q33", - NULL, &intel_g33_driver }, - { PCI_DEVICE_ID_INTEL_PINEVIEW_M_HB, PCI_DEVICE_ID_INTEL_PINEVIEW_M_IG, "GMA3150", - NULL, &intel_g33_driver }, - { PCI_DEVICE_ID_INTEL_PINEVIEW_HB, PCI_DEVICE_ID_INTEL_PINEVIEW_IG, "GMA3150", - NULL, &intel_g33_driver }, - { PCI_DEVICE_ID_INTEL_GM45_HB, PCI_DEVICE_ID_INTEL_GM45_IG, - "GM45", NULL, &intel_i965_driver }, - { PCI_DEVICE_ID_INTEL_EAGLELAKE_HB, PCI_DEVICE_ID_INTEL_EAGLELAKE_IG, - "Eaglelake", NULL, &intel_i965_driver }, - { PCI_DEVICE_ID_INTEL_Q45_HB, PCI_DEVICE_ID_INTEL_Q45_IG, - "Q45/Q43", NULL, &intel_i965_driver }, - { PCI_DEVICE_ID_INTEL_G45_HB, PCI_DEVICE_ID_INTEL_G45_IG, - "G45/G43", NULL, &intel_i965_driver }, - { PCI_DEVICE_ID_INTEL_B43_HB, PCI_DEVICE_ID_INTEL_B43_IG, - "B43", NULL, &intel_i965_driver }, - { PCI_DEVICE_ID_INTEL_G41_HB, PCI_DEVICE_ID_INTEL_G41_IG, - "G41", NULL, &intel_i965_driver }, - { PCI_DEVICE_ID_INTEL_IRONLAKE_D_HB, PCI_DEVICE_ID_INTEL_IRONLAKE_D_IG, - "HD Graphics", NULL, &intel_i965_driver }, - { PCI_DEVICE_ID_INTEL_IRONLAKE_M_HB, PCI_DEVICE_ID_INTEL_IRONLAKE_M_IG, - "HD Graphics", NULL, &intel_i965_driver }, - { PCI_DEVICE_ID_INTEL_IRONLAKE_MA_HB, PCI_DEVICE_ID_INTEL_IRONLAKE_M_IG, - "HD Graphics", NULL, &intel_i965_driver }, - { PCI_DEVICE_ID_INTEL_IRONLAKE_MC2_HB, PCI_DEVICE_ID_INTEL_IRONLAKE_M_IG, - "HD Graphics", NULL, &intel_i965_driver }, - { PCI_DEVICE_ID_INTEL_SANDYBRIDGE_HB, PCI_DEVICE_ID_INTEL_SANDYBRIDGE_GT1_IG, - "Sandybridge", NULL, &intel_gen6_driver }, - { PCI_DEVICE_ID_INTEL_SANDYBRIDGE_HB, PCI_DEVICE_ID_INTEL_SANDYBRIDGE_GT2_IG, - "Sandybridge", NULL, &intel_gen6_driver }, - { PCI_DEVICE_ID_INTEL_SANDYBRIDGE_HB, PCI_DEVICE_ID_INTEL_SANDYBRIDGE_GT2_PLUS_IG, - "Sandybridge", NULL, &intel_gen6_driver }, - { PCI_DEVICE_ID_INTEL_SANDYBRIDGE_M_HB, PCI_DEVICE_ID_INTEL_SANDYBRIDGE_M_GT1_IG, - "Sandybridge", NULL, &intel_gen6_driver }, - { PCI_DEVICE_ID_INTEL_SANDYBRIDGE_M_HB, PCI_DEVICE_ID_INTEL_SANDYBRIDGE_M_GT2_IG, - "Sandybridge", NULL, &intel_gen6_driver }, - { PCI_DEVICE_ID_INTEL_SANDYBRIDGE_M_HB, PCI_DEVICE_ID_INTEL_SANDYBRIDGE_M_GT2_PLUS_IG, - "Sandybridge", NULL, &intel_gen6_driver }, - { PCI_DEVICE_ID_INTEL_SANDYBRIDGE_S_HB, PCI_DEVICE_ID_INTEL_SANDYBRIDGE_S_IG, - "Sandybridge", NULL, &intel_gen6_driver }, - { 0, 0, NULL, NULL, NULL } + { PCI_DEVICE_ID_INTEL_82443LX_0, "440LX", &intel_generic_driver }, + { PCI_DEVICE_ID_INTEL_82443BX_0, "440BX", &intel_generic_driver }, + { PCI_DEVICE_ID_INTEL_82443GX_0, "440GX", &intel_generic_driver }, + { PCI_DEVICE_ID_INTEL_82815_MC, "i815", &intel_815_driver }, + { PCI_DEVICE_ID_INTEL_82820_HB, "i820", &intel_820_driver }, + { PCI_DEVICE_ID_INTEL_82820_UP_HB, "i820", &intel_820_driver }, + { PCI_DEVICE_ID_INTEL_82830_HB, "830M", &intel_830mp_driver }, + { PCI_DEVICE_ID_INTEL_82840_HB, "i840", &intel_840_driver }, + { PCI_DEVICE_ID_INTEL_82845_HB, "845G", &intel_845_driver }, + { PCI_DEVICE_ID_INTEL_82845G_HB, "830M", &intel_845_driver }, + { PCI_DEVICE_ID_INTEL_82850_HB, "i850", &intel_850_driver }, + { PCI_DEVICE_ID_INTEL_82854_HB, "854", &intel_845_driver }, + { PCI_DEVICE_ID_INTEL_82855PM_HB, "855PM", &intel_845_driver }, + { PCI_DEVICE_ID_INTEL_82855GM_HB, "855GM", &intel_845_driver }, + { PCI_DEVICE_ID_INTEL_82860_HB, "i860", &intel_860_driver }, + { PCI_DEVICE_ID_INTEL_82865_HB, "865", &intel_845_driver }, + { PCI_DEVICE_ID_INTEL_82875_HB, "i875", &intel_845_driver }, + { PCI_DEVICE_ID_INTEL_7505_0, "E7505", &intel_7505_driver }, + { PCI_DEVICE_ID_INTEL_7205_0, "E7205", &intel_7505_driver }, + { 0, NULL, NULL } }; -static int __devinit intel_gmch_probe(struct pci_dev *pdev, - struct agp_bridge_data *bridge) -{ - int i, mask; - - bridge->driver = NULL; - - for (i = 0; intel_agp_chipsets[i].name != NULL; i++) { - if ((intel_agp_chipsets[i].gmch_chip_id != 0) && - find_gmch(intel_agp_chipsets[i].gmch_chip_id)) { - bridge->driver = - intel_agp_chipsets[i].gmch_driver; - break; - } - } - - if (!bridge->driver) - return 0; - - bridge->dev_private_data = &intel_private; - bridge->dev = pdev; - - dev_info(&pdev->dev, "Intel %s Chipset\n", intel_agp_chipsets[i].name); - - if (bridge->driver->mask_memory == intel_gen6_mask_memory) - mask = 40; - else if (bridge->driver->mask_memory == intel_i965_mask_memory) - mask = 36; - else - mask = 32; - - if (pci_set_dma_mask(intel_private.pcidev, DMA_BIT_MASK(mask))) - dev_err(&intel_private.pcidev->dev, - "set gfx device dma mask %d-bit failed!\n", mask); - else - pci_set_consistent_dma_mask(intel_private.pcidev, - DMA_BIT_MASK(mask)); - - return 1; -} - static int __devinit agp_intel_probe(struct pci_dev *pdev, const struct pci_device_id *ent) { @@ -903,7 +763,7 @@ static int __devinit agp_intel_probe(struct pci_dev *pdev, } } - if (intel_agp_chipsets[i].name == NULL) { + if (!bridge->driver) { if (cap_ptr) dev_warn(&pdev->dev, "unsupported Intel chipset [%04x/%04x]\n", pdev->vendor, pdev->device); @@ -911,14 +771,6 @@ static int __devinit agp_intel_probe(struct pci_dev *pdev, return -ENODEV; } - if (!bridge->driver) { - if (cap_ptr) - dev_warn(&pdev->dev, "can't find bridge device (chip_id: %04x)\n", - intel_agp_chipsets[i].gmch_chip_id); - agp_put_bridge(bridge); - return -ENODEV; - } - bridge->dev = pdev; bridge->dev_private_data = NULL; @@ -970,8 +822,7 @@ static void __devexit agp_intel_remove(struct pci_dev *pdev) agp_remove_bridge(bridge); - if (intel_private.pcidev) - pci_dev_put(intel_private.pcidev); + intel_gmch_remove(pdev); agp_put_bridge(bridge); } diff --git a/drivers/char/agp/intel-gtt.c b/drivers/char/agp/intel-gtt.c index 75e0a34..6a89ab8 100644 --- a/drivers/char/agp/intel-gtt.c +++ b/drivers/char/agp/intel-gtt.c @@ -1648,3 +1648,127 @@ static const struct agp_bridge_driver intel_g33_driver = { .agp_unmap_memory = intel_agp_unmap_memory, #endif }; + +/* Table to describe Intel GMCH and AGP/PCIE GART drivers. At least one of + * driver and gmch_driver must be non-null, and find_gmch will determine + * which one should be used if a gmch_chip_id is present. + */ +static const struct intel_gtt_driver_description { + unsigned int gmch_chip_id; + char *name; + const struct agp_bridge_driver *gmch_driver; +} intel_gtt_chipsets[] = { + { PCI_DEVICE_ID_INTEL_82810_IG1, "i810", &intel_810_driver }, + { PCI_DEVICE_ID_INTEL_82810_IG3, "i810", &intel_810_driver }, + { PCI_DEVICE_ID_INTEL_82810E_IG, "i810", &intel_810_driver }, + { PCI_DEVICE_ID_INTEL_82815_CGC, "i815", &intel_810_driver }, + { PCI_DEVICE_ID_INTEL_82830_CGC, "830M", &intel_830_driver }, + { PCI_DEVICE_ID_INTEL_82845G_IG, "830M", &intel_830_driver }, + { PCI_DEVICE_ID_INTEL_82854_IG, "854", &intel_830_driver }, + { PCI_DEVICE_ID_INTEL_82855GM_IG, "855GM", &intel_830_driver }, + { PCI_DEVICE_ID_INTEL_82865_IG, "865", &intel_830_driver }, + { PCI_DEVICE_ID_INTEL_E7221_IG, "E7221 (i915)", &intel_915_driver }, + { PCI_DEVICE_ID_INTEL_82915G_IG, "915G", &intel_915_driver }, + { PCI_DEVICE_ID_INTEL_82915GM_IG, "915GM", &intel_915_driver }, + { PCI_DEVICE_ID_INTEL_82945G_IG, "945G", &intel_915_driver }, + { PCI_DEVICE_ID_INTEL_82945GM_IG, "945GM", &intel_915_driver }, + { PCI_DEVICE_ID_INTEL_82945GME_IG, "945GME", &intel_915_driver }, + { PCI_DEVICE_ID_INTEL_82946GZ_IG, "946GZ", &intel_i965_driver }, + { PCI_DEVICE_ID_INTEL_82G35_IG, "G35", &intel_i965_driver }, + { PCI_DEVICE_ID_INTEL_82965Q_IG, "965Q", &intel_i965_driver }, + { PCI_DEVICE_ID_INTEL_82965G_IG, "965G", &intel_i965_driver }, + { PCI_DEVICE_ID_INTEL_82965GM_IG, "965GM", &intel_i965_driver }, + { PCI_DEVICE_ID_INTEL_82965GME_IG, "965GME/GLE", &intel_i965_driver }, + { PCI_DEVICE_ID_INTEL_G33_IG, "G33", &intel_g33_driver }, + { PCI_DEVICE_ID_INTEL_Q35_IG, "Q35", &intel_g33_driver }, + { PCI_DEVICE_ID_INTEL_Q33_IG, "Q33", &intel_g33_driver }, + { PCI_DEVICE_ID_INTEL_PINEVIEW_M_IG, "GMA3150", &intel_g33_driver }, + { PCI_DEVICE_ID_INTEL_PINEVIEW_IG, "GMA3150", &intel_g33_driver }, + { PCI_DEVICE_ID_INTEL_GM45_IG, "GM45", &intel_i965_driver }, + { PCI_DEVICE_ID_INTEL_EAGLELAKE_IG, "Eaglelake", &intel_i965_driver }, + { PCI_DEVICE_ID_INTEL_Q45_IG, "Q45/Q43", &intel_i965_driver }, + { PCI_DEVICE_ID_INTEL_G45_IG, "G45/G43", &intel_i965_driver }, + { PCI_DEVICE_ID_INTEL_B43_IG, "B43", &intel_i965_driver }, + { PCI_DEVICE_ID_INTEL_G41_IG, "G41", &intel_i965_driver }, + { PCI_DEVICE_ID_INTEL_IRONLAKE_D_IG, + "HD Graphics", &intel_i965_driver }, + { PCI_DEVICE_ID_INTEL_IRONLAKE_M_IG, + "HD Graphics", &intel_i965_driver }, + { PCI_DEVICE_ID_INTEL_SANDYBRIDGE_GT1_IG, + "Sandybridge", &intel_gen6_driver }, + { PCI_DEVICE_ID_INTEL_SANDYBRIDGE_GT2_IG, + "Sandybridge", &intel_gen6_driver }, + { PCI_DEVICE_ID_INTEL_SANDYBRIDGE_GT2_PLUS_IG, + "Sandybridge", &intel_gen6_driver }, + { PCI_DEVICE_ID_INTEL_SANDYBRIDGE_M_GT1_IG, + "Sandybridge", &intel_gen6_driver }, + { PCI_DEVICE_ID_INTEL_SANDYBRIDGE_M_GT2_IG, + "Sandybridge", &intel_gen6_driver }, + { PCI_DEVICE_ID_INTEL_SANDYBRIDGE_M_GT2_PLUS_IG, + "Sandybridge", &intel_gen6_driver }, + { PCI_DEVICE_ID_INTEL_SANDYBRIDGE_S_IG, + "Sandybridge", &intel_gen6_driver }, + { 0, NULL, NULL } +}; + +static int find_gmch(u16 device) +{ + struct pci_dev *gmch_device; + + gmch_device = pci_get_device(PCI_VENDOR_ID_INTEL, device, NULL); + if (gmch_device && PCI_FUNC(gmch_device->devfn) != 0) { + gmch_device = pci_get_device(PCI_VENDOR_ID_INTEL, + device, gmch_device); + } + + if (!gmch_device) + return 0; + + intel_private.pcidev = gmch_device; + return 1; +} + +int __devinit intel_gmch_probe(struct pci_dev *pdev, + struct agp_bridge_data *bridge) +{ + int i, mask; + bridge->driver = NULL; + + for (i = 0; intel_gtt_chipsets[i].name != NULL; i++) { + if (find_gmch(intel_gtt_chipsets[i].gmch_chip_id)) { + bridge->driver = + intel_gtt_chipsets[i].gmch_driver; + break; + } + } + + if (!bridge->driver) + return 0; + + bridge->dev_private_data = &intel_private; + bridge->dev = pdev; + + dev_info(&pdev->dev, "Intel %s Chipset\n", intel_gtt_chipsets[i].name); + + if (bridge->driver->mask_memory == intel_gen6_mask_memory) + mask = 40; + else if (bridge->driver->mask_memory == intel_i965_mask_memory) + mask = 36; + else + mask = 32; + + if (pci_set_dma_mask(intel_private.pcidev, DMA_BIT_MASK(mask))) + dev_err(&intel_private.pcidev->dev, + "set gfx device dma mask %d-bit failed!\n", mask); + else + pci_set_consistent_dma_mask(intel_private.pcidev, + DMA_BIT_MASK(mask)); + + return 1; +} + +void __devexit intel_gmch_remove(struct pci_dev *pdev) +{ + if (intel_private.pcidev) + pci_dev_put(intel_private.pcidev); +} -- cgit v1.1 From e2404e7c3fe6f46e161edf085c6d9bea06ebe488 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Wed, 8 Sep 2010 17:29:51 +0200 Subject: agp/intel: make intel-gtt.c into a real source file Now that the disentangling is complete, stop including intel-gtt.c from intel-agp.c. The linux build system _really_ doesn't allow .c source files with the same name as the module. It fails with the following message when trying to build such a bugger: make[3]: Circular drivers/char/agp/intel-agp.o <- drivers/char/agp/intel-agp.o dependency dropped. Instead of renameing intel-agp.c I've simply created a new module out of intel-gtt.c. Renaming intel-agp.ko to something else is not an option for it will surely kill someones boot process. This also paves the way to use the gtt code without loading the agp driver. Signed-off-by: Daniel Vetter Signed-off-by: Chris Wilson --- drivers/char/agp/Makefile | 1 + drivers/char/agp/intel-agp.c | 3 --- drivers/char/agp/intel-agp.h | 3 +++ drivers/char/agp/intel-gtt.c | 20 ++++++++++++++++++-- 4 files changed, 22 insertions(+), 5 deletions(-) diff --git a/drivers/char/agp/Makefile b/drivers/char/agp/Makefile index 627f542..8eb56e2 100644 --- a/drivers/char/agp/Makefile +++ b/drivers/char/agp/Makefile @@ -13,6 +13,7 @@ obj-$(CONFIG_AGP_HP_ZX1) += hp-agp.o obj-$(CONFIG_AGP_PARISC) += parisc-agp.o obj-$(CONFIG_AGP_I460) += i460-agp.o obj-$(CONFIG_AGP_INTEL) += intel-agp.o +obj-$(CONFIG_AGP_INTEL) += intel-gtt.o obj-$(CONFIG_AGP_NVIDIA) += nvidia-agp.o obj-$(CONFIG_AGP_SGI_TIOCA) += sgi-agp.o obj-$(CONFIG_AGP_SIS) += sis-agp.o diff --git a/drivers/char/agp/intel-agp.c b/drivers/char/agp/intel-agp.c index c818a4d..5cd2221 100644 --- a/drivers/char/agp/intel-agp.c +++ b/drivers/char/agp/intel-agp.c @@ -12,9 +12,6 @@ #include #include "agp.h" #include "intel-agp.h" -#include - -#include "intel-gtt.c" int intel_agp_enabled; EXPORT_SYMBOL(intel_agp_enabled); diff --git a/drivers/char/agp/intel-agp.h b/drivers/char/agp/intel-agp.h index ee189c7..bf03afc 100644 --- a/drivers/char/agp/intel-agp.h +++ b/drivers/char/agp/intel-agp.h @@ -253,4 +253,7 @@ agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_IRONLAKE_MC2_HB || \ IS_SNB) +int intel_gmch_probe(struct pci_dev *pdev, + struct agp_bridge_data *bridge); +void intel_gmch_remove(struct pci_dev *pdev); #endif diff --git a/drivers/char/agp/intel-gtt.c b/drivers/char/agp/intel-gtt.c index 6a89ab8..72f9376 100644 --- a/drivers/char/agp/intel-gtt.c +++ b/drivers/char/agp/intel-gtt.c @@ -15,6 +15,17 @@ * /fairy-tale-mode off */ +#include +#include +#include +#include +#include +#include +#include +#include "agp.h" +#include "intel-agp.h" +#include + /* * If we have Intel graphics, we're not going to have anything other than * an Intel IOMMU. So make the correct use of the PCI DMA API contingent @@ -1728,7 +1739,7 @@ static int find_gmch(u16 device) return 1; } -int __devinit intel_gmch_probe(struct pci_dev *pdev, +int intel_gmch_probe(struct pci_dev *pdev, struct agp_bridge_data *bridge) { int i, mask; @@ -1766,9 +1777,14 @@ int __devinit intel_gmch_probe(struct pci_dev *pdev, return 1; } +EXPORT_SYMBOL(intel_gmch_probe); -void __devexit intel_gmch_remove(struct pci_dev *pdev) +void intel_gmch_remove(struct pci_dev *pdev) { if (intel_private.pcidev) pci_dev_put(intel_private.pcidev); } +EXPORT_SYMBOL(intel_gmch_remove); + +MODULE_AUTHOR("Dave Jones "); +MODULE_LICENSE("GPL and additional rights"); -- cgit v1.1 From 0ade638655f0ef4d807295c14a4c97544bd6b9ca Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Tue, 24 Aug 2010 22:18:41 +0200 Subject: intel-gtt: introduce drm/intel-gtt.h Add a few definitions to it that are already shared and that will be shared in the future (like the number of stolen entries). No functional changes in here. Signed-off-by: Daniel Vetter Signed-off-by: Chris Wilson --- drivers/char/agp/intel-gtt.c | 42 +++++++++++++++++++---------------------- drivers/gpu/drm/i915/i915_dma.c | 2 -- drivers/gpu/drm/i915/i915_drv.h | 1 + include/drm/intel-gtt.h | 18 ++++++++++++++++++ 4 files changed, 38 insertions(+), 25 deletions(-) create mode 100644 include/drm/intel-gtt.h diff --git a/drivers/char/agp/intel-gtt.c b/drivers/char/agp/intel-gtt.c index 72f9376..0a3e91b 100644 --- a/drivers/char/agp/intel-gtt.c +++ b/drivers/char/agp/intel-gtt.c @@ -25,6 +25,7 @@ #include "agp.h" #include "intel-agp.h" #include +#include /* * If we have Intel graphics, we're not going to have anything other than @@ -81,17 +82,11 @@ static struct gatt_mask intel_gen6_masks[] = }; static struct _intel_private { + struct intel_gtt base; struct pci_dev *pcidev; /* device one */ u8 __iomem *registers; u32 __iomem *gtt; /* I915G */ int num_dcache_entries; - /* gtt_entries is the number of gtt entries that are already mapped - * to stolen memory. Stolen memory is larger than the memory mapped - * through gtt_entries, as it includes some reserved space for the BIOS - * popup and for the GTT. - */ - int gtt_entries; /* i830+ */ - int gtt_total_size; union { void __iomem *i9xx_flush_page; void *i8xx_flush_page; @@ -772,7 +767,7 @@ static void intel_i830_init_gtt_entries(void) gtt_entries = 0; } - intel_private.gtt_entries = gtt_entries; + intel_private.base.gtt_stolen_entries = gtt_entries; } static void intel_i830_fini_flush(void) @@ -849,7 +844,7 @@ static int intel_i830_create_gatt_table(struct agp_bridge_data *bridge) /* we have to call this as early as possible after the MMIO base address is known */ intel_i830_init_gtt_entries(); - if (intel_private.gtt_entries == 0) { + if (intel_private.base.gtt_stolen_entries == 0) { iounmap(intel_private.registers); return -ENOMEM; } @@ -919,7 +914,7 @@ static int intel_i830_configure(void) readl(intel_private.registers+I810_PGETBL_CTL); /* PCI Posting. */ if (agp_bridge->driver->needs_scratch_page) { - for (i = intel_private.gtt_entries; i < current_size->num_entries; i++) { + for (i = intel_private.base.gtt_stolen_entries; i < current_size->num_entries; i++) { writel(agp_bridge->scratch_page, intel_private.registers+I810_PTE_BASE+(i*4)); } readl(intel_private.registers+I810_PTE_BASE+((i-1)*4)); /* PCI Posting. */ @@ -950,10 +945,10 @@ static int intel_i830_insert_entries(struct agp_memory *mem, off_t pg_start, temp = agp_bridge->current_size; num_entries = A_SIZE_FIX(temp)->num_entries; - if (pg_start < intel_private.gtt_entries) { + if (pg_start < intel_private.base.gtt_stolen_entries) { dev_printk(KERN_DEBUG, &intel_private.pcidev->dev, - "pg_start == 0x%.8lx, intel_private.gtt_entries == 0x%.8x\n", - pg_start, intel_private.gtt_entries); + "pg_start == 0x%.8lx, gtt_stolen_entries == 0x%.8x\n", + pg_start, intel_private.base.gtt_stolen_entries); dev_info(&intel_private.pcidev->dev, "trying to insert into local/stolen memory\n"); @@ -1001,7 +996,7 @@ static int intel_i830_remove_entries(struct agp_memory *mem, off_t pg_start, if (mem->page_count == 0) return 0; - if (pg_start < intel_private.gtt_entries) { + if (pg_start < intel_private.base.gtt_stolen_entries) { dev_info(&intel_private.pcidev->dev, "trying to disable local/stolen memory\n"); return -EINVAL; @@ -1136,7 +1131,8 @@ static int intel_i9xx_configure(void) readl(intel_private.registers+I810_PGETBL_CTL); /* PCI Posting. */ if (agp_bridge->driver->needs_scratch_page) { - for (i = intel_private.gtt_entries; i < intel_private.gtt_total_size; i++) { + for (i = intel_private.base.gtt_stolen_entries; i < + intel_private.base.gtt_total_entries; i++) { writel(agp_bridge->scratch_page, intel_private.gtt+i); } readl(intel_private.gtt+i-1); /* PCI Posting. */ @@ -1181,10 +1177,10 @@ static int intel_i915_insert_entries(struct agp_memory *mem, off_t pg_start, temp = agp_bridge->current_size; num_entries = A_SIZE_FIX(temp)->num_entries; - if (pg_start < intel_private.gtt_entries) { + if (pg_start < intel_private.base.gtt_stolen_entries) { dev_printk(KERN_DEBUG, &intel_private.pcidev->dev, - "pg_start == 0x%.8lx, intel_private.gtt_entries == 0x%.8x\n", - pg_start, intel_private.gtt_entries); + "pg_start == 0x%.8lx, gtt_stolen_entries == 0x%.8x\n", + pg_start, intel_private.base.gtt_stolen_entries); dev_info(&intel_private.pcidev->dev, "trying to insert into local/stolen memory\n"); @@ -1227,7 +1223,7 @@ static int intel_i915_remove_entries(struct agp_memory *mem, off_t pg_start, if (mem->page_count == 0) return 0; - if (pg_start < intel_private.gtt_entries) { + if (pg_start < intel_private.base.gtt_stolen_entries) { dev_info(&intel_private.pcidev->dev, "trying to disable local/stolen memory\n"); return -EINVAL; @@ -1323,7 +1319,7 @@ static int intel_i915_create_gatt_table(struct agp_bridge_data *bridge) if (!intel_private.gtt) return -ENOMEM; - intel_private.gtt_total_size = gtt_map_size / 4; + intel_private.base.gtt_total_entries = gtt_map_size / 4; temp &= 0xfff80000; @@ -1338,7 +1334,7 @@ static int intel_i915_create_gatt_table(struct agp_bridge_data *bridge) /* we have to call this as early as possible after the MMIO base address is known */ intel_i830_init_gtt_entries(); - if (intel_private.gtt_entries == 0) { + if (intel_private.base.gtt_stolen_entries == 0) { iounmap(intel_private.gtt); iounmap(intel_private.registers); return -ENOMEM; @@ -1449,7 +1445,7 @@ static int intel_i965_create_gatt_table(struct agp_bridge_data *bridge) if (!intel_private.gtt) return -ENOMEM; - intel_private.gtt_total_size = gtt_size / 4; + intel_private.base.gtt_total_entries = gtt_size / 4; intel_private.registers = ioremap(temp, 128 * 4096); if (!intel_private.registers) { @@ -1462,7 +1458,7 @@ static int intel_i965_create_gatt_table(struct agp_bridge_data *bridge) /* we have to call this as early as possible after the MMIO base address is known */ intel_i830_init_gtt_entries(); - if (intel_private.gtt_entries == 0) { + if (intel_private.base.gtt_stolen_entries == 0) { iounmap(intel_private.gtt); iounmap(intel_private.registers); return -ENOMEM; diff --git a/drivers/gpu/drm/i915/i915_dma.c b/drivers/gpu/drm/i915/i915_dma.c index 8d52f01..47228cb16 100644 --- a/drivers/gpu/drm/i915/i915_dma.c +++ b/drivers/gpu/drm/i915/i915_dma.c @@ -42,8 +42,6 @@ #include #include -extern int intel_max_stolen; /* from AGP driver */ - /** * Sets up the hardware status page for devices that need a physical address * in the register. diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index cfc8bfd..d825ef2 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -34,6 +34,7 @@ #include "intel_bios.h" #include "intel_ringbuffer.h" #include +#include /* General customization: */ diff --git a/include/drm/intel-gtt.h b/include/drm/intel-gtt.h new file mode 100644 index 0000000..6769cb7 --- /dev/null +++ b/include/drm/intel-gtt.h @@ -0,0 +1,18 @@ +/* Common header for intel-gtt.ko and i915.ko */ + +#ifndef _DRM_INTEL_GTT_H +#define _DRM_INTEL_GTT_H +extern int intel_max_stolen; /* from AGP driver */ + +struct intel_gtt { + /* Number of stolen gtt entries at the beginning. */ + unsigned int gtt_stolen_entries; + /* Total number of gtt entries. */ + unsigned int gtt_total_entries; + /* Part of the gtt that is mappable by the cpu, for those chips where + * this is not the full gtt. */ + unsigned int gtt_mappable_entries; +}; + +#endif + -- cgit v1.1 From d7cca2f7000243ac43a389110c3d8474f582ae3f Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Tue, 24 Aug 2010 23:06:19 +0200 Subject: intel-gtt: store a local pointer to the bridge pci dev When the intel-gtt code now longer depends on agp, we cannot rely on this. So store a local reference in intel-gtt.c. Signed-off-by: Daniel Vetter Signed-off-by: Chris Wilson --- drivers/char/agp/intel-gtt.c | 61 ++++++++++++++++++++++++-------------------- 1 file changed, 34 insertions(+), 27 deletions(-) diff --git a/drivers/char/agp/intel-gtt.c b/drivers/char/agp/intel-gtt.c index 0a3e91b..96e5fd1 100644 --- a/drivers/char/agp/intel-gtt.c +++ b/drivers/char/agp/intel-gtt.c @@ -84,6 +84,7 @@ static struct gatt_mask intel_gen6_masks[] = static struct _intel_private { struct intel_gtt base; struct pci_dev *pcidev; /* device one */ + struct pci_dev *bridge_dev; u8 __iomem *registers; u32 __iomem *gtt; /* I915G */ int num_dcache_entries; @@ -221,11 +222,12 @@ static int intel_i810_fetch_size(void) u32 smram_miscc; struct aper_size_info_fixed *values; - pci_read_config_dword(agp_bridge->dev, I810_SMRAM_MISCC, &smram_miscc); + pci_read_config_dword(intel_private.bridge_dev, + I810_SMRAM_MISCC, &smram_miscc); values = A_SIZE_FIX(agp_bridge->driver->aperture_sizes); if ((smram_miscc & I810_GMS) == I810_GMS_DISABLE) { - dev_warn(&agp_bridge->dev->dev, "i810 is disabled\n"); + dev_warn(&intel_private.bridge_dev->dev, "i810 is disabled\n"); return 0; } if ((smram_miscc & I810_GFX_MEM_WIN_SIZE) == I810_GFX_MEM_WIN_32M) { @@ -538,7 +540,8 @@ static void intel_i830_init_gtt_entries(void) static const int ddt[4] = { 0, 16, 32, 64 }; int size; /* reserved space (in kb) at the top of stolen memory */ - pci_read_config_word(agp_bridge->dev, I830_GMCH_CTRL, &gmch_ctrl); + pci_read_config_word(intel_private.bridge_dev, + I830_GMCH_CTRL, &gmch_ctrl); if (IS_I965) { u32 pgetbl_ctl; @@ -583,7 +586,7 @@ static void intel_i830_init_gtt_entries(void) size = 2048; break; default: - dev_info(&agp_bridge->dev->dev, + dev_info(&intel_private.bridge_dev->dev, "unknown page table size 0x%x, assuming 512KB\n", (gmch_ctrl & G33_PGETBL_SIZE_MASK)); size = 512; @@ -602,8 +605,8 @@ static void intel_i830_init_gtt_entries(void) size = agp_bridge->driver->fetch_size() + 4; } - if (agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_82830_HB || - agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_82845G_HB) { + if (intel_private.bridge_dev->device == PCI_DEVICE_ID_INTEL_82830_HB || + intel_private.bridge_dev->device == PCI_DEVICE_ID_INTEL_82845G_HB) { switch (gmch_ctrl & I830_GMCH_GMS_MASK) { case I830_GMCH_GMS_STOLEN_512: gtt_entries = KB(512) - KB(size); @@ -753,16 +756,16 @@ static void intel_i830_init_gtt_entries(void) } } if (!local && gtt_entries > intel_max_stolen) { - dev_info(&agp_bridge->dev->dev, + dev_info(&intel_private.bridge_dev->dev, "detected %dK stolen memory, trimming to %dK\n", gtt_entries / KB(1), intel_max_stolen / KB(1)); gtt_entries = intel_max_stolen / KB(4); } else if (gtt_entries > 0) { - dev_info(&agp_bridge->dev->dev, "detected %dK %s memory\n", + dev_info(&intel_private.bridge_dev->dev, "detected %dK %s memory\n", gtt_entries / KB(1), local ? "local" : "stolen"); gtt_entries /= KB(4); } else { - dev_info(&agp_bridge->dev->dev, + dev_info(&intel_private.bridge_dev->dev, "no pre-allocated video memory detected\n"); gtt_entries = 0; } @@ -871,15 +874,15 @@ static int intel_i830_fetch_size(void) values = A_SIZE_FIX(agp_bridge->driver->aperture_sizes); - if (agp_bridge->dev->device != PCI_DEVICE_ID_INTEL_82830_HB && - agp_bridge->dev->device != PCI_DEVICE_ID_INTEL_82845G_HB) { + if (intel_private.bridge_dev->device != PCI_DEVICE_ID_INTEL_82830_HB && + intel_private.bridge_dev->device != PCI_DEVICE_ID_INTEL_82845G_HB) { /* 855GM/852GM/865G has 128MB aperture size */ agp_bridge->current_size = (void *) values; agp_bridge->aperture_size_idx = 0; return values[0].size; } - pci_read_config_word(agp_bridge->dev, I830_GMCH_CTRL, &gmch_ctrl); + pci_read_config_word(intel_private.bridge_dev, I830_GMCH_CTRL, &gmch_ctrl); if ((gmch_ctrl & I830_GMCH_MEM_MASK) == I830_GMCH_MEM_128M) { agp_bridge->current_size = (void *) values; @@ -906,9 +909,9 @@ static int intel_i830_configure(void) pci_read_config_dword(intel_private.pcidev, I810_GMADDR, &temp); agp_bridge->gart_bus_addr = (temp & PCI_BASE_ADDRESS_MEM_MASK); - pci_read_config_word(agp_bridge->dev, I830_GMCH_CTRL, &gmch_ctrl); + pci_read_config_word(intel_private.bridge_dev, I830_GMCH_CTRL, &gmch_ctrl); gmch_ctrl |= I830_GMCH_ENABLED; - pci_write_config_word(agp_bridge->dev, I830_GMCH_CTRL, gmch_ctrl); + pci_write_config_word(intel_private.bridge_dev, I830_GMCH_CTRL, gmch_ctrl); writel(agp_bridge->gatt_bus_addr|I810_PGETBL_ENABLED, intel_private.registers+I810_PGETBL_CTL); readl(intel_private.registers+I810_PGETBL_CTL); /* PCI Posting. */ @@ -1021,9 +1024,9 @@ static struct agp_memory *intel_i830_alloc_by_type(size_t pg_count, int type) static int intel_alloc_chipset_flush_resource(void) { int ret; - ret = pci_bus_alloc_resource(agp_bridge->dev->bus, &intel_private.ifp_resource, PAGE_SIZE, + ret = pci_bus_alloc_resource(intel_private.bridge_dev->bus, &intel_private.ifp_resource, PAGE_SIZE, PAGE_SIZE, PCIBIOS_MIN_MEM, 0, - pcibios_align_resource, agp_bridge->dev); + pcibios_align_resource, intel_private.bridge_dev); return ret; } @@ -1033,11 +1036,11 @@ static void intel_i915_setup_chipset_flush(void) int ret; u32 temp; - pci_read_config_dword(agp_bridge->dev, I915_IFPADDR, &temp); + pci_read_config_dword(intel_private.bridge_dev, I915_IFPADDR, &temp); if (!(temp & 0x1)) { intel_alloc_chipset_flush_resource(); intel_private.resource_valid = 1; - pci_write_config_dword(agp_bridge->dev, I915_IFPADDR, (intel_private.ifp_resource.start & 0xffffffff) | 0x1); + pci_write_config_dword(intel_private.bridge_dev, I915_IFPADDR, (intel_private.ifp_resource.start & 0xffffffff) | 0x1); } else { temp &= ~1; @@ -1056,17 +1059,17 @@ static void intel_i965_g33_setup_chipset_flush(void) u32 temp_hi, temp_lo; int ret; - pci_read_config_dword(agp_bridge->dev, I965_IFPADDR + 4, &temp_hi); - pci_read_config_dword(agp_bridge->dev, I965_IFPADDR, &temp_lo); + pci_read_config_dword(intel_private.bridge_dev, I965_IFPADDR + 4, &temp_hi); + pci_read_config_dword(intel_private.bridge_dev, I965_IFPADDR, &temp_lo); if (!(temp_lo & 0x1)) { intel_alloc_chipset_flush_resource(); intel_private.resource_valid = 1; - pci_write_config_dword(agp_bridge->dev, I965_IFPADDR + 4, + pci_write_config_dword(intel_private.bridge_dev, I965_IFPADDR + 4, upper_32_bits(intel_private.ifp_resource.start)); - pci_write_config_dword(agp_bridge->dev, I965_IFPADDR, (intel_private.ifp_resource.start & 0xffffffff) | 0x1); + pci_write_config_dword(intel_private.bridge_dev, I965_IFPADDR, (intel_private.ifp_resource.start & 0xffffffff) | 0x1); } else { u64 l64; @@ -1123,9 +1126,9 @@ static int intel_i9xx_configure(void) agp_bridge->gart_bus_addr = (temp & PCI_BASE_ADDRESS_MEM_MASK); - pci_read_config_word(agp_bridge->dev, I830_GMCH_CTRL, &gmch_ctrl); + pci_read_config_word(intel_private.bridge_dev, I830_GMCH_CTRL, &gmch_ctrl); gmch_ctrl |= I830_GMCH_ENABLED; - pci_write_config_word(agp_bridge->dev, I830_GMCH_CTRL, gmch_ctrl); + pci_write_config_word(intel_private.bridge_dev, I830_GMCH_CTRL, gmch_ctrl); writel(agp_bridge->gatt_bus_addr|I810_PGETBL_ENABLED, intel_private.registers+I810_PGETBL_CTL); readl(intel_private.registers+I810_PGETBL_CTL); /* PCI Posting. */ @@ -1267,7 +1270,7 @@ static int intel_i915_get_gtt_size(void) u16 gmch_ctrl; /* G33's GTT size defined in gmch_ctrl */ - pci_read_config_word(agp_bridge->dev, I830_GMCH_CTRL, &gmch_ctrl); + pci_read_config_word(intel_private.bridge_dev, I830_GMCH_CTRL, &gmch_ctrl); switch (gmch_ctrl & I830_GMCH_GMS_MASK) { case I830_GMCH_GMS_STOLEN_512: size = 512; @@ -1279,7 +1282,7 @@ static int intel_i915_get_gtt_size(void) size = 8*1024; break; default: - dev_info(&agp_bridge->dev->dev, + dev_info(&intel_private.bridge_dev->dev, "unknown page table size 0x%x, assuming 512KB\n", (gmch_ctrl & I830_GMCH_GMS_MASK)); size = 512; @@ -1380,7 +1383,7 @@ static void intel_i965_get_gtt_range(int *gtt_offset, int *gtt_size) { u16 snb_gmch_ctl; - switch (agp_bridge->dev->device) { + switch (intel_private.bridge_dev->device) { case PCI_DEVICE_ID_INTEL_GM45_HB: case PCI_DEVICE_ID_INTEL_EAGLELAKE_HB: case PCI_DEVICE_ID_INTEL_Q45_HB: @@ -1755,6 +1758,8 @@ int intel_gmch_probe(struct pci_dev *pdev, bridge->dev_private_data = &intel_private; bridge->dev = pdev; + intel_private.bridge_dev = pci_dev_get(pdev); + dev_info(&pdev->dev, "Intel %s Chipset\n", intel_gtt_chipsets[i].name); if (bridge->driver->mask_memory == intel_gen6_mask_memory) @@ -1779,6 +1784,8 @@ void intel_gmch_remove(struct pci_dev *pdev) { if (intel_private.pcidev) pci_dev_put(intel_private.pcidev); + if (intel_private.bridge_dev) + pci_dev_put(intel_private.bridge_dev); } EXPORT_SYMBOL(intel_gmch_remove); -- cgit v1.1 From bfde067bebe72293b1f909a8b35ee8d82811f8f5 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Tue, 24 Aug 2010 23:07:59 +0200 Subject: intel-gtt: s/intel_i830_init_gtt_entries/intel_gtt_stolen_entries First simple step towards a more generic initialization. This is needed to disentangle the agp stuff from the stuff that is actually needed by drm/i915. Signed-off-by: Daniel Vetter Signed-off-by: Chris Wilson --- drivers/char/agp/intel-gtt.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/drivers/char/agp/intel-gtt.c b/drivers/char/agp/intel-gtt.c index 96e5fd1..9edeb06 100644 --- a/drivers/char/agp/intel-gtt.c +++ b/drivers/char/agp/intel-gtt.c @@ -531,10 +531,10 @@ static struct aper_size_info_fixed intel_i830_sizes[] = {512, 131072, 7}, }; -static void intel_i830_init_gtt_entries(void) +static unsigned int intel_gtt_stolen_entries(void) { u16 gmch_ctrl; - int gtt_entries = 0; + unsigned int gtt_entries = 0; u8 rdct; int local = 0; static const int ddt[4] = { 0, 16, 32, 64 }; @@ -770,7 +770,7 @@ static void intel_i830_init_gtt_entries(void) gtt_entries = 0; } - intel_private.base.gtt_stolen_entries = gtt_entries; + return gtt_entries; } static void intel_i830_fini_flush(void) @@ -846,7 +846,7 @@ static int intel_i830_create_gatt_table(struct agp_bridge_data *bridge) global_cache_flush(); /* FIXME: ?? */ /* we have to call this as early as possible after the MMIO base address is known */ - intel_i830_init_gtt_entries(); + intel_private.base.gtt_stolen_entries = intel_gtt_stolen_entries(); if (intel_private.base.gtt_stolen_entries == 0) { iounmap(intel_private.registers); return -ENOMEM; @@ -1336,7 +1336,7 @@ static int intel_i915_create_gatt_table(struct agp_bridge_data *bridge) global_cache_flush(); /* FIXME: ? */ /* we have to call this as early as possible after the MMIO base address is known */ - intel_i830_init_gtt_entries(); + intel_private.base.gtt_stolen_entries = intel_gtt_stolen_entries(); if (intel_private.base.gtt_stolen_entries == 0) { iounmap(intel_private.gtt); iounmap(intel_private.registers); @@ -1460,7 +1460,7 @@ static int intel_i965_create_gatt_table(struct agp_bridge_data *bridge) global_cache_flush(); /* FIXME: ? */ /* we have to call this as early as possible after the MMIO base address is known */ - intel_i830_init_gtt_entries(); + intel_private.base.gtt_stolen_entries = intel_gtt_stolen_entries(); if (intel_private.base.gtt_stolen_entries == 0) { iounmap(intel_private.gtt); iounmap(intel_private.registers); -- cgit v1.1 From 1784a5fb4f7a41b9a5ea066f7782418bfe170c04 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Wed, 8 Sep 2010 21:01:04 +0200 Subject: intel-gtt: new function intel_gtt_mappable_entries This implementation is stolen from drm/i915, but is equivalent to the code sprinkled over intel-gtt.c in the various fetch_size functions. It's not yet used anywhere, though. Also introduce intel_gtt_init which only calls intel_gtt_stolen_entries. Over the course of the next patches, this will grow untill it contains the complete init sequence starting from the call to gtt_mappable_entries. Signed-off-by: Daniel Vetter Signed-off-by: Chris Wilson --- drivers/char/agp/intel-gtt.c | 78 +++++++++++++++++++++++++++++++++----------- 1 file changed, 59 insertions(+), 19 deletions(-) diff --git a/drivers/char/agp/intel-gtt.c b/drivers/char/agp/intel-gtt.c index 9edeb06..932ede8 100644 --- a/drivers/char/agp/intel-gtt.c +++ b/drivers/char/agp/intel-gtt.c @@ -755,6 +755,7 @@ static unsigned int intel_gtt_stolen_entries(void) break; } } + if (!local && gtt_entries > intel_max_stolen) { dev_info(&intel_private.bridge_dev->dev, "detected %dK stolen memory, trimming to %dK\n", @@ -773,6 +774,47 @@ static unsigned int intel_gtt_stolen_entries(void) return gtt_entries; } +static unsigned int intel_gtt_mappable_entries(void) +{ + unsigned int aperture_size; + u16 gmch_ctrl; + + aperture_size = 1024 * 1024; + + pci_read_config_word(intel_private.bridge_dev, + I830_GMCH_CTRL, &gmch_ctrl); + + switch (intel_private.pcidev->device) { + case PCI_DEVICE_ID_INTEL_82830_CGC: + case PCI_DEVICE_ID_INTEL_82845G_IG: + case PCI_DEVICE_ID_INTEL_82855GM_IG: + case PCI_DEVICE_ID_INTEL_82865_IG: + if ((gmch_ctrl & I830_GMCH_MEM_MASK) == I830_GMCH_MEM_64M) + aperture_size *= 64; + else + aperture_size *= 128; + break; + default: + /* 9xx supports large sizes, just look at the length */ + aperture_size = pci_resource_len(intel_private.pcidev, 2); + break; + } + + return aperture_size >> PAGE_SHIFT; +} + +static int intel_gtt_init(void) +{ + /* we have to call this as early as possible after the MMIO base address is known */ + intel_private.base.gtt_stolen_entries = intel_gtt_stolen_entries(); + if (intel_private.base.gtt_stolen_entries == 0) { + iounmap(intel_private.registers); + return -ENOMEM; + } + + return 0; +} + static void intel_i830_fini_flush(void) { kunmap(intel_private.i8xx_page); @@ -825,7 +867,7 @@ static void intel_i830_chipset_flush(struct agp_bridge_data *bridge) */ static int intel_i830_create_gatt_table(struct agp_bridge_data *bridge) { - int page_order; + int page_order, ret; struct aper_size_info_fixed *size; int num_entries; u32 temp; @@ -845,12 +887,9 @@ static int intel_i830_create_gatt_table(struct agp_bridge_data *bridge) temp = readl(intel_private.registers+I810_PGETBL_CTL) & 0xfffff000; global_cache_flush(); /* FIXME: ?? */ - /* we have to call this as early as possible after the MMIO base address is known */ - intel_private.base.gtt_stolen_entries = intel_gtt_stolen_entries(); - if (intel_private.base.gtt_stolen_entries == 0) { - iounmap(intel_private.registers); - return -ENOMEM; - } + ret = intel_gtt_init(); + if (ret != 0) + return ret; agp_bridge->gatt_table = NULL; @@ -1302,7 +1341,7 @@ static int intel_i915_get_gtt_size(void) */ static int intel_i915_create_gatt_table(struct agp_bridge_data *bridge) { - int page_order; + int page_order, ret; struct aper_size_info_fixed *size; int num_entries; u32 temp, temp2; @@ -1335,12 +1374,10 @@ static int intel_i915_create_gatt_table(struct agp_bridge_data *bridge) temp = readl(intel_private.registers+I810_PGETBL_CTL) & 0xfffff000; global_cache_flush(); /* FIXME: ? */ - /* we have to call this as early as possible after the MMIO base address is known */ - intel_private.base.gtt_stolen_entries = intel_gtt_stolen_entries(); - if (intel_private.base.gtt_stolen_entries == 0) { + ret = intel_gtt_init(); + if (ret != 0) { iounmap(intel_private.gtt); - iounmap(intel_private.registers); - return -ENOMEM; + return ret; } agp_bridge->gatt_table = NULL; @@ -1426,7 +1463,7 @@ static void intel_i965_get_gtt_range(int *gtt_offset, int *gtt_size) */ static int intel_i965_create_gatt_table(struct agp_bridge_data *bridge) { - int page_order; + int page_order, ret; struct aper_size_info_fixed *size; int num_entries; u32 temp; @@ -1459,12 +1496,10 @@ static int intel_i965_create_gatt_table(struct agp_bridge_data *bridge) temp = readl(intel_private.registers+I810_PGETBL_CTL) & 0xfffff000; global_cache_flush(); /* FIXME: ? */ - /* we have to call this as early as possible after the MMIO base address is known */ - intel_private.base.gtt_stolen_entries = intel_gtt_stolen_entries(); - if (intel_private.base.gtt_stolen_entries == 0) { + ret = intel_gtt_init(); + if (ret != 0) { iounmap(intel_private.gtt); - iounmap(intel_private.registers); - return -ENOMEM; + return ret; } agp_bridge->gatt_table = NULL; @@ -1776,6 +1811,11 @@ int intel_gmch_probe(struct pci_dev *pdev, pci_set_consistent_dma_mask(intel_private.pcidev, DMA_BIT_MASK(mask)); + if (bridge->driver == &intel_810_driver) + return 1; + + intel_private.base.gtt_mappable_entries = intel_gtt_mappable_entries(); + return 1; } EXPORT_SYMBOL(intel_gmch_probe); -- cgit v1.1 From 3e921f980fdd5b972efb7f368b2a847a01804184 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Fri, 27 Aug 2010 15:33:26 +0200 Subject: intel-gtt: generic intel_fake_agp_fetch_size This uses the new mappable gtt size detection from the previous patch. Signed-off-by: Daniel Vetter Signed-off-by: Chris Wilson --- drivers/char/agp/intel-gtt.c | 77 ++++++++++++++------------------------------ 1 file changed, 24 insertions(+), 53 deletions(-) diff --git a/drivers/char/agp/intel-gtt.c b/drivers/char/agp/intel-gtt.c index 932ede8..a997a20 100644 --- a/drivers/char/agp/intel-gtt.c +++ b/drivers/char/agp/intel-gtt.c @@ -815,6 +815,25 @@ static int intel_gtt_init(void) return 0; } +static int intel_fake_agp_fetch_size(void) +{ + unsigned int aper_size; + int i; + int num_sizes = ARRAY_SIZE(intel_i830_sizes); + + aper_size = (intel_private.base.gtt_mappable_entries << PAGE_SHIFT) + / MB(1); + + for (i = 0; i < num_sizes; i++) { + if (aper_size == intel_i830_sizes[i].size) { + agp_bridge->current_size = intel_i830_sizes + i; + return aper_size; + } + } + + return 0; +} + static void intel_i830_fini_flush(void) { kunmap(intel_private.i8xx_page); @@ -906,36 +925,6 @@ static int intel_i830_free_gatt_table(struct agp_bridge_data *bridge) return 0; } -static int intel_i830_fetch_size(void) -{ - u16 gmch_ctrl; - struct aper_size_info_fixed *values; - - values = A_SIZE_FIX(agp_bridge->driver->aperture_sizes); - - if (intel_private.bridge_dev->device != PCI_DEVICE_ID_INTEL_82830_HB && - intel_private.bridge_dev->device != PCI_DEVICE_ID_INTEL_82845G_HB) { - /* 855GM/852GM/865G has 128MB aperture size */ - agp_bridge->current_size = (void *) values; - agp_bridge->aperture_size_idx = 0; - return values[0].size; - } - - pci_read_config_word(intel_private.bridge_dev, I830_GMCH_CTRL, &gmch_ctrl); - - if ((gmch_ctrl & I830_GMCH_MEM_MASK) == I830_GMCH_MEM_128M) { - agp_bridge->current_size = (void *) values; - agp_bridge->aperture_size_idx = 0; - return values[0].size; - } else { - agp_bridge->current_size = (void *) (values + 1); - agp_bridge->aperture_size_idx = 1; - return values[1].size; - } - - return 0; -} - static int intel_i830_configure(void) { struct aper_size_info_fixed *current_size; @@ -1283,24 +1272,6 @@ static int intel_i915_remove_entries(struct agp_memory *mem, off_t pg_start, * described in the spec of the MSAC registers is just changing of the * resource size. */ -static int intel_i9xx_fetch_size(void) -{ - int num_sizes = ARRAY_SIZE(intel_i830_sizes); - int aper_size; /* size in megabytes */ - int i; - - aper_size = pci_resource_len(intel_private.pcidev, 2) / MB(1); - - for (i = 0; i < num_sizes; i++) { - if (aper_size == intel_i830_sizes[i].size) { - agp_bridge->current_size = intel_i830_sizes + i; - return aper_size; - } - } - - return 0; -} - static int intel_i915_get_gtt_size(void) { int size; @@ -1542,7 +1513,7 @@ static const struct agp_bridge_driver intel_830_driver = { .num_aperture_sizes = 4, .needs_scratch_page = true, .configure = intel_i830_configure, - .fetch_size = intel_i830_fetch_size, + .fetch_size = intel_fake_agp_fetch_size, .cleanup = intel_i830_cleanup, .mask_memory = intel_i810_mask_memory, .masks = intel_i810_masks, @@ -1569,7 +1540,7 @@ static const struct agp_bridge_driver intel_915_driver = { .num_aperture_sizes = 4, .needs_scratch_page = true, .configure = intel_i9xx_configure, - .fetch_size = intel_i9xx_fetch_size, + .fetch_size = intel_fake_agp_fetch_size, .cleanup = intel_i915_cleanup, .mask_memory = intel_i810_mask_memory, .masks = intel_i810_masks, @@ -1602,7 +1573,7 @@ static const struct agp_bridge_driver intel_i965_driver = { .num_aperture_sizes = 4, .needs_scratch_page = true, .configure = intel_i9xx_configure, - .fetch_size = intel_i9xx_fetch_size, + .fetch_size = intel_fake_agp_fetch_size, .cleanup = intel_i915_cleanup, .mask_memory = intel_i965_mask_memory, .masks = intel_i810_masks, @@ -1635,7 +1606,7 @@ static const struct agp_bridge_driver intel_gen6_driver = { .num_aperture_sizes = 4, .needs_scratch_page = true, .configure = intel_i9xx_configure, - .fetch_size = intel_i9xx_fetch_size, + .fetch_size = intel_fake_agp_fetch_size, .cleanup = intel_i915_cleanup, .mask_memory = intel_gen6_mask_memory, .masks = intel_gen6_masks, @@ -1668,7 +1639,7 @@ static const struct agp_bridge_driver intel_g33_driver = { .num_aperture_sizes = 4, .needs_scratch_page = true, .configure = intel_i9xx_configure, - .fetch_size = intel_i9xx_fetch_size, + .fetch_size = intel_fake_agp_fetch_size, .cleanup = intel_i915_cleanup, .mask_memory = intel_i965_mask_memory, .masks = intel_i810_masks, -- cgit v1.1 From d8d9abcd35aeebd633cba2e99c384f4e004ccb84 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Fri, 27 Aug 2010 16:13:52 +0200 Subject: intel-gtt: sane variable names for intel_gtt_stolen_entries This somewhat aligns it with the version in drm/i915/i915_dma.c. Changes: - s/gtt_entries/stolen_size - track overhead entries in a seperate var (the effective gtt size calculation will be extracted later on). - subtract the overhead at the end instead of in each clause. Signed-off-by: Daniel Vetter Signed-off-by: Chris Wilson --- drivers/char/agp/intel-gtt.c | 108 ++++++++++++++++++++++--------------------- 1 file changed, 56 insertions(+), 52 deletions(-) diff --git a/drivers/char/agp/intel-gtt.c b/drivers/char/agp/intel-gtt.c index a997a20..79eb106 100644 --- a/drivers/char/agp/intel-gtt.c +++ b/drivers/char/agp/intel-gtt.c @@ -534,11 +534,12 @@ static struct aper_size_info_fixed intel_i830_sizes[] = static unsigned int intel_gtt_stolen_entries(void) { u16 gmch_ctrl; - unsigned int gtt_entries = 0; u8 rdct; int local = 0; static const int ddt[4] = { 0, 16, 32, 64 }; int size; /* reserved space (in kb) at the top of stolen memory */ + unsigned int overhead_entries, stolen_entries; + unsigned int stolen_size = 0; pci_read_config_word(intel_private.bridge_dev, I830_GMCH_CTRL, &gmch_ctrl); @@ -605,26 +606,28 @@ static unsigned int intel_gtt_stolen_entries(void) size = agp_bridge->driver->fetch_size() + 4; } + overhead_entries = size/4; + if (intel_private.bridge_dev->device == PCI_DEVICE_ID_INTEL_82830_HB || intel_private.bridge_dev->device == PCI_DEVICE_ID_INTEL_82845G_HB) { switch (gmch_ctrl & I830_GMCH_GMS_MASK) { case I830_GMCH_GMS_STOLEN_512: - gtt_entries = KB(512) - KB(size); + stolen_size = KB(512); break; case I830_GMCH_GMS_STOLEN_1024: - gtt_entries = MB(1) - KB(size); + stolen_size = MB(1); break; case I830_GMCH_GMS_STOLEN_8192: - gtt_entries = MB(8) - KB(size); + stolen_size = MB(8); break; case I830_GMCH_GMS_LOCAL: rdct = readb(intel_private.registers+I830_RDRAM_CHANNEL_TYPE); - gtt_entries = (I830_RDRAM_ND(rdct) + 1) * + stolen_size = (I830_RDRAM_ND(rdct) + 1) * MB(ddt[I830_RDRAM_DDT(rdct)]); local = 1; break; default: - gtt_entries = 0; + stolen_size = 0; break; } } else if (IS_SNB) { @@ -635,143 +638,144 @@ static unsigned int intel_gtt_stolen_entries(void) pci_read_config_word(intel_private.pcidev, SNB_GMCH_CTRL, &snb_gmch_ctl); switch (snb_gmch_ctl & SNB_GMCH_GMS_STOLEN_MASK) { case SNB_GMCH_GMS_STOLEN_32M: - gtt_entries = MB(32) - KB(size); + stolen_size = MB(32); break; case SNB_GMCH_GMS_STOLEN_64M: - gtt_entries = MB(64) - KB(size); + stolen_size = MB(64); break; case SNB_GMCH_GMS_STOLEN_96M: - gtt_entries = MB(96) - KB(size); + stolen_size = MB(96); break; case SNB_GMCH_GMS_STOLEN_128M: - gtt_entries = MB(128) - KB(size); + stolen_size = MB(128); break; case SNB_GMCH_GMS_STOLEN_160M: - gtt_entries = MB(160) - KB(size); + stolen_size = MB(160); break; case SNB_GMCH_GMS_STOLEN_192M: - gtt_entries = MB(192) - KB(size); + stolen_size = MB(192); break; case SNB_GMCH_GMS_STOLEN_224M: - gtt_entries = MB(224) - KB(size); + stolen_size = MB(224); break; case SNB_GMCH_GMS_STOLEN_256M: - gtt_entries = MB(256) - KB(size); + stolen_size = MB(256); break; case SNB_GMCH_GMS_STOLEN_288M: - gtt_entries = MB(288) - KB(size); + stolen_size = MB(288); break; case SNB_GMCH_GMS_STOLEN_320M: - gtt_entries = MB(320) - KB(size); + stolen_size = MB(320); break; case SNB_GMCH_GMS_STOLEN_352M: - gtt_entries = MB(352) - KB(size); + stolen_size = MB(352); break; case SNB_GMCH_GMS_STOLEN_384M: - gtt_entries = MB(384) - KB(size); + stolen_size = MB(384); break; case SNB_GMCH_GMS_STOLEN_416M: - gtt_entries = MB(416) - KB(size); + stolen_size = MB(416); break; case SNB_GMCH_GMS_STOLEN_448M: - gtt_entries = MB(448) - KB(size); + stolen_size = MB(448); break; case SNB_GMCH_GMS_STOLEN_480M: - gtt_entries = MB(480) - KB(size); + stolen_size = MB(480); break; case SNB_GMCH_GMS_STOLEN_512M: - gtt_entries = MB(512) - KB(size); + stolen_size = MB(512); break; } } else { switch (gmch_ctrl & I855_GMCH_GMS_MASK) { case I855_GMCH_GMS_STOLEN_1M: - gtt_entries = MB(1) - KB(size); + stolen_size = MB(1); break; case I855_GMCH_GMS_STOLEN_4M: - gtt_entries = MB(4) - KB(size); + stolen_size = MB(4); break; case I855_GMCH_GMS_STOLEN_8M: - gtt_entries = MB(8) - KB(size); + stolen_size = MB(8); break; case I855_GMCH_GMS_STOLEN_16M: - gtt_entries = MB(16) - KB(size); + stolen_size = MB(16); break; case I855_GMCH_GMS_STOLEN_32M: - gtt_entries = MB(32) - KB(size); + stolen_size = MB(32); break; case I915_GMCH_GMS_STOLEN_48M: /* Check it's really I915G */ if (IS_I915 || IS_I965 || IS_G33 || IS_G4X) - gtt_entries = MB(48) - KB(size); + stolen_size = MB(48); else - gtt_entries = 0; + stolen_size = 0; break; case I915_GMCH_GMS_STOLEN_64M: /* Check it's really I915G */ if (IS_I915 || IS_I965 || IS_G33 || IS_G4X) - gtt_entries = MB(64) - KB(size); + stolen_size = MB(64); else - gtt_entries = 0; + stolen_size = 0; break; case G33_GMCH_GMS_STOLEN_128M: if (IS_G33 || IS_I965 || IS_G4X) - gtt_entries = MB(128) - KB(size); + stolen_size = MB(128); else - gtt_entries = 0; + stolen_size = 0; break; case G33_GMCH_GMS_STOLEN_256M: if (IS_G33 || IS_I965 || IS_G4X) - gtt_entries = MB(256) - KB(size); + stolen_size = MB(256); else - gtt_entries = 0; + stolen_size = 0; break; case INTEL_GMCH_GMS_STOLEN_96M: if (IS_I965 || IS_G4X) - gtt_entries = MB(96) - KB(size); + stolen_size = MB(96); else - gtt_entries = 0; + stolen_size = 0; break; case INTEL_GMCH_GMS_STOLEN_160M: if (IS_I965 || IS_G4X) - gtt_entries = MB(160) - KB(size); + stolen_size = MB(160); else - gtt_entries = 0; + stolen_size = 0; break; case INTEL_GMCH_GMS_STOLEN_224M: if (IS_I965 || IS_G4X) - gtt_entries = MB(224) - KB(size); + stolen_size = MB(224); else - gtt_entries = 0; + stolen_size = 0; break; case INTEL_GMCH_GMS_STOLEN_352M: if (IS_I965 || IS_G4X) - gtt_entries = MB(352) - KB(size); + stolen_size = MB(352); else - gtt_entries = 0; + stolen_size = 0; break; default: - gtt_entries = 0; + stolen_size = 0; break; } } - if (!local && gtt_entries > intel_max_stolen) { + if (!local && stolen_size > intel_max_stolen) { dev_info(&intel_private.bridge_dev->dev, "detected %dK stolen memory, trimming to %dK\n", - gtt_entries / KB(1), intel_max_stolen / KB(1)); - gtt_entries = intel_max_stolen / KB(4); - } else if (gtt_entries > 0) { + stolen_size / KB(1), intel_max_stolen / KB(1)); + stolen_size = intel_max_stolen; + } else if (stolen_size > 0) { dev_info(&intel_private.bridge_dev->dev, "detected %dK %s memory\n", - gtt_entries / KB(1), local ? "local" : "stolen"); - gtt_entries /= KB(4); + stolen_size / KB(1), local ? "local" : "stolen"); } else { dev_info(&intel_private.bridge_dev->dev, "no pre-allocated video memory detected\n"); - gtt_entries = 0; + stolen_size = 0; } - return gtt_entries; + stolen_entries = stolen_size/KB(4) - overhead_entries; + + return stolen_entries; } static unsigned int intel_gtt_mappable_entries(void) -- cgit v1.1 From 77ad498ecaeb9a614d2a7bbfaab58a35c0cc577d Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Fri, 27 Aug 2010 16:25:54 +0200 Subject: intel-gtt: drop unnecessary conditions in intel_gtt_stolen_entries The dedection function in drm/i915/i915_dma.c works without it, so drop it here, too. All the values are disdinct, anyway. Signed-off-by: Daniel Vetter Signed-off-by: Chris Wilson --- drivers/char/agp/intel-gtt.c | 42 ++++++++---------------------------------- 1 file changed, 8 insertions(+), 34 deletions(-) diff --git a/drivers/char/agp/intel-gtt.c b/drivers/char/agp/intel-gtt.c index 79eb106..a620296 100644 --- a/drivers/char/agp/intel-gtt.c +++ b/drivers/char/agp/intel-gtt.c @@ -704,54 +704,28 @@ static unsigned int intel_gtt_stolen_entries(void) stolen_size = MB(32); break; case I915_GMCH_GMS_STOLEN_48M: - /* Check it's really I915G */ - if (IS_I915 || IS_I965 || IS_G33 || IS_G4X) - stolen_size = MB(48); - else - stolen_size = 0; + stolen_size = MB(48); break; case I915_GMCH_GMS_STOLEN_64M: - /* Check it's really I915G */ - if (IS_I915 || IS_I965 || IS_G33 || IS_G4X) - stolen_size = MB(64); - else - stolen_size = 0; + stolen_size = MB(64); break; case G33_GMCH_GMS_STOLEN_128M: - if (IS_G33 || IS_I965 || IS_G4X) - stolen_size = MB(128); - else - stolen_size = 0; + stolen_size = MB(128); break; case G33_GMCH_GMS_STOLEN_256M: - if (IS_G33 || IS_I965 || IS_G4X) - stolen_size = MB(256); - else - stolen_size = 0; + stolen_size = MB(256); break; case INTEL_GMCH_GMS_STOLEN_96M: - if (IS_I965 || IS_G4X) - stolen_size = MB(96); - else - stolen_size = 0; + stolen_size = MB(96); break; case INTEL_GMCH_GMS_STOLEN_160M: - if (IS_I965 || IS_G4X) - stolen_size = MB(160); - else - stolen_size = 0; + stolen_size = MB(160); break; case INTEL_GMCH_GMS_STOLEN_224M: - if (IS_I965 || IS_G4X) - stolen_size = MB(224); - else - stolen_size = 0; + stolen_size = MB(224); break; case INTEL_GMCH_GMS_STOLEN_352M: - if (IS_I965 || IS_G4X) - stolen_size = MB(352); - else - stolen_size = 0; + stolen_size = MB(352); break; default: stolen_size = 0; -- cgit v1.1 From fbe407836b5c8d82c68195962240a392d0ce64ea Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Fri, 27 Aug 2010 17:12:41 +0200 Subject: intel-gtt: adjust overhead entries in intel_gtt_stolen_entries agp/intel_gtt.c and drm/i915/i915_dma.c don't calculate this the same way: The intel-gtt code seems to use the actual gtt size, the drm module just the mappable. Go with the logic from the drm module because that's the more conservative choice. But conserve the original code in intel_gtt_total_size for later use. Signed-off-by: Daniel Vetter Signed-off-by: Chris Wilson --- drivers/char/agp/intel-gtt.c | 141 ++++++++++++++++++++++++------------------- 1 file changed, 78 insertions(+), 63 deletions(-) diff --git a/drivers/char/agp/intel-gtt.c b/drivers/char/agp/intel-gtt.c index a620296..04e052e 100644 --- a/drivers/char/agp/intel-gtt.c +++ b/drivers/char/agp/intel-gtt.c @@ -537,76 +537,19 @@ static unsigned int intel_gtt_stolen_entries(void) u8 rdct; int local = 0; static const int ddt[4] = { 0, 16, 32, 64 }; - int size; /* reserved space (in kb) at the top of stolen memory */ unsigned int overhead_entries, stolen_entries; unsigned int stolen_size = 0; pci_read_config_word(intel_private.bridge_dev, I830_GMCH_CTRL, &gmch_ctrl); - if (IS_I965) { - u32 pgetbl_ctl; - pgetbl_ctl = readl(intel_private.registers+I810_PGETBL_CTL); - - /* The 965 has a field telling us the size of the GTT, - * which may be larger than what is necessary to map the - * aperture. - */ - switch (pgetbl_ctl & I965_PGETBL_SIZE_MASK) { - case I965_PGETBL_SIZE_128KB: - size = 128; - break; - case I965_PGETBL_SIZE_256KB: - size = 256; - break; - case I965_PGETBL_SIZE_512KB: - size = 512; - break; - case I965_PGETBL_SIZE_1MB: - size = 1024; - break; - case I965_PGETBL_SIZE_2MB: - size = 2048; - break; - case I965_PGETBL_SIZE_1_5MB: - size = 1024 + 512; - break; - default: - dev_info(&intel_private.pcidev->dev, - "unknown page table size, assuming 512KB\n"); - size = 512; - } - size += 4; /* add in BIOS popup space */ - } else if (IS_G33 && !IS_PINEVIEW) { - /* G33's GTT size defined in gmch_ctrl */ - switch (gmch_ctrl & G33_PGETBL_SIZE_MASK) { - case G33_PGETBL_SIZE_1M: - size = 1024; - break; - case G33_PGETBL_SIZE_2M: - size = 2048; - break; - default: - dev_info(&intel_private.bridge_dev->dev, - "unknown page table size 0x%x, assuming 512KB\n", - (gmch_ctrl & G33_PGETBL_SIZE_MASK)); - size = 512; - } - size += 4; - } else if (IS_G4X || IS_PINEVIEW) { - /* On 4 series hardware, GTT stolen is separate from graphics - * stolen, ignore it in stolen gtt entries counting. However, - * 4KB of the stolen memory doesn't get mapped to the GTT. - */ - size = 4; - } else { - /* On previous hardware, the GTT size was just what was - * required to map the aperture. - */ - size = agp_bridge->driver->fetch_size() + 4; - } + if (IS_G4X || IS_PINEVIEW) + overhead_entries = 0; + else + overhead_entries = intel_private.base.gtt_mappable_entries + / 1024; - overhead_entries = size/4; + overhead_entries += 1; /* BIOS popup */ if (intel_private.bridge_dev->device == PCI_DEVICE_ID_INTEL_82830_HB || intel_private.bridge_dev->device == PCI_DEVICE_ID_INTEL_82845G_HB) { @@ -752,6 +695,78 @@ static unsigned int intel_gtt_stolen_entries(void) return stolen_entries; } +#if 0 /* extracted code in bad shape, needs some cleaning before use */ +static unsigned int intel_gtt_total_entries(void) +{ + int size; + u16 gmch_ctrl; + + if (IS_I965) { + u32 pgetbl_ctl; + pgetbl_ctl = readl(intel_private.registers+I810_PGETBL_CTL); + + /* The 965 has a field telling us the size of the GTT, + * which may be larger than what is necessary to map the + * aperture. + */ + switch (pgetbl_ctl & I965_PGETBL_SIZE_MASK) { + case I965_PGETBL_SIZE_128KB: + size = 128; + break; + case I965_PGETBL_SIZE_256KB: + size = 256; + break; + case I965_PGETBL_SIZE_512KB: + size = 512; + break; + case I965_PGETBL_SIZE_1MB: + size = 1024; + break; + case I965_PGETBL_SIZE_2MB: + size = 2048; + break; + case I965_PGETBL_SIZE_1_5MB: + size = 1024 + 512; + break; + default: + dev_info(&intel_private.pcidev->dev, + "unknown page table size, assuming 512KB\n"); + size = 512; + } + size += 4; /* add in BIOS popup space */ + } else if (IS_G33 && !IS_PINEVIEW) { + /* G33's GTT size defined in gmch_ctrl */ + switch (gmch_ctrl & G33_PGETBL_SIZE_MASK) { + case G33_PGETBL_SIZE_1M: + size = 1024; + break; + case G33_PGETBL_SIZE_2M: + size = 2048; + break; + default: + dev_info(&intel_private.bridge_dev->dev, + "unknown page table size 0x%x, assuming 512KB\n", + (gmch_ctrl & G33_PGETBL_SIZE_MASK)); + size = 512; + } + size += 4; + } else if (IS_G4X || IS_PINEVIEW) { + /* On 4 series hardware, GTT stolen is separate from graphics + * stolen, ignore it in stolen gtt entries counting. However, + * 4KB of the stolen memory doesn't get mapped to the GTT. + */ + size = 4; + } else { + /* On previous hardware, the GTT size was just what was + * required to map the aperture. + */ + size = agp_bridge->driver->fetch_size() + 4; + } + + return size/KB(4); +} +#endif + static unsigned int intel_gtt_mappable_entries(void) { unsigned int aperture_size; -- cgit v1.1 From ffdd7510b0bd5ec663b6b11b39810574f2ce3111 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Fri, 27 Aug 2010 17:51:29 +0200 Subject: intel-gtt: s/i8[13]0/fake_agp for generic functions Start to separate the fake agp driver from the rest of intel-gtt.c Signed-off-by: Daniel Vetter Signed-off-by: Chris Wilson --- drivers/char/agp/intel-gtt.c | 57 ++++++++++++++++++++++---------------------- 1 file changed, 29 insertions(+), 28 deletions(-) diff --git a/drivers/char/agp/intel-gtt.c b/drivers/char/agp/intel-gtt.c index 04e052e..56bcf27 100644 --- a/drivers/char/agp/intel-gtt.c +++ b/drivers/char/agp/intel-gtt.c @@ -292,7 +292,7 @@ static void intel_i810_cleanup(void) iounmap(intel_private.registers); } -static void intel_i810_agp_enable(struct agp_bridge_data *bridge, u32 mode) +static void intel_fake_agp_enable(struct agp_bridge_data *bridge, u32 mode) { return; } @@ -522,7 +522,7 @@ static unsigned long intel_i810_mask_memory(struct agp_bridge_data *bridge, return addr | bridge->driver->masks[type].mask; } -static struct aper_size_info_fixed intel_i830_sizes[] = +static struct aper_size_info_fixed intel_fake_agp_sizes[] = { {128, 32768, 5}, /* The 64M mode still requires a 128k gatt */ @@ -812,14 +812,14 @@ static int intel_fake_agp_fetch_size(void) { unsigned int aper_size; int i; - int num_sizes = ARRAY_SIZE(intel_i830_sizes); + int num_sizes = ARRAY_SIZE(intel_fake_agp_sizes); aper_size = (intel_private.base.gtt_mappable_entries << PAGE_SHIFT) / MB(1); for (i = 0; i < num_sizes; i++) { - if (aper_size == intel_i830_sizes[i].size) { - agp_bridge->current_size = intel_i830_sizes + i; + if (aper_size == intel_fake_agp_sizes[i].size) { + agp_bridge->current_size = intel_fake_agp_sizes + i; return aper_size; } } @@ -913,7 +913,7 @@ static int intel_i830_create_gatt_table(struct agp_bridge_data *bridge) /* Return the gatt table to a sane state. Use the top of stolen * memory for the GTT. */ -static int intel_i830_free_gatt_table(struct agp_bridge_data *bridge) +static int intel_fake_agp_free_gatt_table(struct agp_bridge_data *bridge) { return 0; } @@ -1034,7 +1034,8 @@ static int intel_i830_remove_entries(struct agp_memory *mem, off_t pg_start, return 0; } -static struct agp_memory *intel_i830_alloc_by_type(size_t pg_count, int type) +static struct agp_memory *intel_fake_agp_alloc_by_type(size_t pg_count, + int type) { if (type == AGP_PHYS_MEMORY) return alloc_agpphysmem_i8xx(pg_count, type); @@ -1484,7 +1485,7 @@ static const struct agp_bridge_driver intel_810_driver = { .cleanup = intel_i810_cleanup, .mask_memory = intel_i810_mask_memory, .masks = intel_i810_masks, - .agp_enable = intel_i810_agp_enable, + .agp_enable = intel_fake_agp_enable, .cache_flush = global_cache_flush, .create_gatt_table = agp_generic_create_gatt_table, .free_gatt_table = agp_generic_free_gatt_table, @@ -1501,7 +1502,7 @@ static const struct agp_bridge_driver intel_810_driver = { static const struct agp_bridge_driver intel_830_driver = { .owner = THIS_MODULE, - .aperture_sizes = intel_i830_sizes, + .aperture_sizes = intel_fake_agp_sizes, .size_type = FIXED_APER_SIZE, .num_aperture_sizes = 4, .needs_scratch_page = true, @@ -1510,13 +1511,13 @@ static const struct agp_bridge_driver intel_830_driver = { .cleanup = intel_i830_cleanup, .mask_memory = intel_i810_mask_memory, .masks = intel_i810_masks, - .agp_enable = intel_i810_agp_enable, + .agp_enable = intel_fake_agp_enable, .cache_flush = global_cache_flush, .create_gatt_table = intel_i830_create_gatt_table, - .free_gatt_table = intel_i830_free_gatt_table, + .free_gatt_table = intel_fake_agp_free_gatt_table, .insert_memory = intel_i830_insert_entries, .remove_memory = intel_i830_remove_entries, - .alloc_by_type = intel_i830_alloc_by_type, + .alloc_by_type = intel_fake_agp_alloc_by_type, .free_by_type = intel_i810_free_by_type, .agp_alloc_page = agp_generic_alloc_page, .agp_alloc_pages = agp_generic_alloc_pages, @@ -1528,7 +1529,7 @@ static const struct agp_bridge_driver intel_830_driver = { static const struct agp_bridge_driver intel_915_driver = { .owner = THIS_MODULE, - .aperture_sizes = intel_i830_sizes, + .aperture_sizes = intel_fake_agp_sizes, .size_type = FIXED_APER_SIZE, .num_aperture_sizes = 4, .needs_scratch_page = true, @@ -1537,13 +1538,13 @@ static const struct agp_bridge_driver intel_915_driver = { .cleanup = intel_i915_cleanup, .mask_memory = intel_i810_mask_memory, .masks = intel_i810_masks, - .agp_enable = intel_i810_agp_enable, + .agp_enable = intel_fake_agp_enable, .cache_flush = global_cache_flush, .create_gatt_table = intel_i915_create_gatt_table, - .free_gatt_table = intel_i830_free_gatt_table, + .free_gatt_table = intel_fake_agp_free_gatt_table, .insert_memory = intel_i915_insert_entries, .remove_memory = intel_i915_remove_entries, - .alloc_by_type = intel_i830_alloc_by_type, + .alloc_by_type = intel_fake_agp_alloc_by_type, .free_by_type = intel_i810_free_by_type, .agp_alloc_page = agp_generic_alloc_page, .agp_alloc_pages = agp_generic_alloc_pages, @@ -1561,7 +1562,7 @@ static const struct agp_bridge_driver intel_915_driver = { static const struct agp_bridge_driver intel_i965_driver = { .owner = THIS_MODULE, - .aperture_sizes = intel_i830_sizes, + .aperture_sizes = intel_fake_agp_sizes, .size_type = FIXED_APER_SIZE, .num_aperture_sizes = 4, .needs_scratch_page = true, @@ -1570,13 +1571,13 @@ static const struct agp_bridge_driver intel_i965_driver = { .cleanup = intel_i915_cleanup, .mask_memory = intel_i965_mask_memory, .masks = intel_i810_masks, - .agp_enable = intel_i810_agp_enable, + .agp_enable = intel_fake_agp_enable, .cache_flush = global_cache_flush, .create_gatt_table = intel_i965_create_gatt_table, - .free_gatt_table = intel_i830_free_gatt_table, + .free_gatt_table = intel_fake_agp_free_gatt_table, .insert_memory = intel_i915_insert_entries, .remove_memory = intel_i915_remove_entries, - .alloc_by_type = intel_i830_alloc_by_type, + .alloc_by_type = intel_fake_agp_alloc_by_type, .free_by_type = intel_i810_free_by_type, .agp_alloc_page = agp_generic_alloc_page, .agp_alloc_pages = agp_generic_alloc_pages, @@ -1594,7 +1595,7 @@ static const struct agp_bridge_driver intel_i965_driver = { static const struct agp_bridge_driver intel_gen6_driver = { .owner = THIS_MODULE, - .aperture_sizes = intel_i830_sizes, + .aperture_sizes = intel_fake_agp_sizes, .size_type = FIXED_APER_SIZE, .num_aperture_sizes = 4, .needs_scratch_page = true, @@ -1603,13 +1604,13 @@ static const struct agp_bridge_driver intel_gen6_driver = { .cleanup = intel_i915_cleanup, .mask_memory = intel_gen6_mask_memory, .masks = intel_gen6_masks, - .agp_enable = intel_i810_agp_enable, + .agp_enable = intel_fake_agp_enable, .cache_flush = global_cache_flush, .create_gatt_table = intel_i965_create_gatt_table, - .free_gatt_table = intel_i830_free_gatt_table, + .free_gatt_table = intel_fake_agp_free_gatt_table, .insert_memory = intel_i915_insert_entries, .remove_memory = intel_i915_remove_entries, - .alloc_by_type = intel_i830_alloc_by_type, + .alloc_by_type = intel_fake_agp_alloc_by_type, .free_by_type = intel_i810_free_by_type, .agp_alloc_page = agp_generic_alloc_page, .agp_alloc_pages = agp_generic_alloc_pages, @@ -1627,7 +1628,7 @@ static const struct agp_bridge_driver intel_gen6_driver = { static const struct agp_bridge_driver intel_g33_driver = { .owner = THIS_MODULE, - .aperture_sizes = intel_i830_sizes, + .aperture_sizes = intel_fake_agp_sizes, .size_type = FIXED_APER_SIZE, .num_aperture_sizes = 4, .needs_scratch_page = true, @@ -1636,13 +1637,13 @@ static const struct agp_bridge_driver intel_g33_driver = { .cleanup = intel_i915_cleanup, .mask_memory = intel_i965_mask_memory, .masks = intel_i810_masks, - .agp_enable = intel_i810_agp_enable, + .agp_enable = intel_fake_agp_enable, .cache_flush = global_cache_flush, .create_gatt_table = intel_i915_create_gatt_table, - .free_gatt_table = intel_i830_free_gatt_table, + .free_gatt_table = intel_fake_agp_free_gatt_table, .insert_memory = intel_i915_insert_entries, .remove_memory = intel_i915_remove_entries, - .alloc_by_type = intel_i830_alloc_by_type, + .alloc_by_type = intel_fake_agp_alloc_by_type, .free_by_type = intel_i810_free_by_type, .agp_alloc_page = agp_generic_alloc_page, .agp_alloc_pages = agp_generic_alloc_pages, -- cgit v1.1 From e5e408fc94595aab897f613b6f4e2f5b36870a6f Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Sat, 28 Aug 2010 11:04:32 +0200 Subject: intel-gtt: fix gtt_total_entries detection In commit f1befe71 Chris Wilson added some code to clear the full gtt on g33/pineview instead of just the mappable part. The code looks like it was copy-pasted from agp/intel-gtt.c, at least an identical piece of code is still there (in intel_i830_init_gtt_entries). This lead to a regression in 2.6.35 which was supposedly fixed in commit e7b96f28 Now this commit makes absolutely no sense to me. It seems to be slightly confused about chipset generations - it references docs for 4th gen but the regression concerns 3rd gen g33. Luckily the the g33 gmch docs are available with the GMCH Graphics Control pci config register definitions. The other (bigger problem) is that the new check in there uses the i830 stolen mem bits (.5M, 1M or 8M of stolen mem). They are different since the i855GM. The most likely case is that it hits the 512M fallback, which was probably the right thing for the boxes this was tested on. So the original approach by Chris Wilson seems to be wrong and the current code is definitely wrong. There is a third approach by Jesse Barnes from his RFC patch "Who wants a bigger GTT mapping range?" where he simply shoves g33 in the same clause like later chipset generations. I've asked him and Jesse confirmed that this should work. So implement it. Bugzilla: https://bugzilla.kernel.org/show_bug.cgi?id=16891$ Tested-by: Anisse Astier Cc: stable@kernel.org Signed-off-by: Daniel Vetter Signed-off-by: Chris Wilson --- drivers/char/agp/intel-gtt.c | 50 ++++++++++---------------------------------- 1 file changed, 11 insertions(+), 39 deletions(-) diff --git a/drivers/char/agp/intel-gtt.c b/drivers/char/agp/intel-gtt.c index 56bcf27..3b84d84 100644 --- a/drivers/char/agp/intel-gtt.c +++ b/drivers/char/agp/intel-gtt.c @@ -699,71 +699,43 @@ static unsigned int intel_gtt_stolen_entries(void) static unsigned int intel_gtt_total_entries(void) { int size; - u16 gmch_ctrl; - if (IS_I965) { + if (IS_G33 || IS_I965 || IS_G4X) { u32 pgetbl_ctl; pgetbl_ctl = readl(intel_private.registers+I810_PGETBL_CTL); - /* The 965 has a field telling us the size of the GTT, - * which may be larger than what is necessary to map the - * aperture. - */ switch (pgetbl_ctl & I965_PGETBL_SIZE_MASK) { case I965_PGETBL_SIZE_128KB: - size = 128; + size = KB(128); break; case I965_PGETBL_SIZE_256KB: - size = 256; + size = KB(256); break; case I965_PGETBL_SIZE_512KB: - size = 512; + size = KB(512); break; case I965_PGETBL_SIZE_1MB: - size = 1024; + size = KB(1024); break; case I965_PGETBL_SIZE_2MB: - size = 2048; + size = KB(2048); break; case I965_PGETBL_SIZE_1_5MB: - size = 1024 + 512; + size = KB(1024 + 512); break; default: dev_info(&intel_private.pcidev->dev, "unknown page table size, assuming 512KB\n"); - size = 512; - } - size += 4; /* add in BIOS popup space */ - } else if (IS_G33 && !IS_PINEVIEW) { - /* G33's GTT size defined in gmch_ctrl */ - switch (gmch_ctrl & G33_PGETBL_SIZE_MASK) { - case G33_PGETBL_SIZE_1M: - size = 1024; - break; - case G33_PGETBL_SIZE_2M: - size = 2048; - break; - default: - dev_info(&intel_private.bridge_dev->dev, - "unknown page table size 0x%x, assuming 512KB\n", - (gmch_ctrl & G33_PGETBL_SIZE_MASK)); - size = 512; + size = KB(512); } - size += 4; - } else if (IS_G4X || IS_PINEVIEW) { - /* On 4 series hardware, GTT stolen is separate from graphics - * stolen, ignore it in stolen gtt entries counting. However, - * 4KB of the stolen memory doesn't get mapped to the GTT. - */ - size = 4; + + return size/4; } else { /* On previous hardware, the GTT size was just what was * required to map the aperture. */ - size = agp_bridge->driver->fetch_size() + 4; + return intel_private.base.gtt_mappable_entries; } - - return size/KB(4); } #endif -- cgit v1.1 From 1a997ff2a0089a07a5494545d31f4366742dea43 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Wed, 8 Sep 2010 21:18:53 +0200 Subject: intel-gtt: introduce intel_gtt_driver Same idea as INTEL_INFO from drm/i915. This - reduces the dependancy on agp_driver - stops the what-does-IS_I965G-mean confusion (here it's just gen4, in drm/i915 it's gen >=4) - further prepares the separation of the fake agp driver from the rest. Signed-off-by: Daniel Vetter Signed-off-by: Chris Wilson --- drivers/char/agp/intel-agp.h | 40 ----------- drivers/char/agp/intel-gtt.c | 167 +++++++++++++++++++++++++++++++------------ 2 files changed, 120 insertions(+), 87 deletions(-) diff --git a/drivers/char/agp/intel-agp.h b/drivers/char/agp/intel-agp.h index bf03afc..ef7ca97 100644 --- a/drivers/char/agp/intel-agp.h +++ b/drivers/char/agp/intel-agp.h @@ -213,46 +213,6 @@ #define PCI_DEVICE_ID_INTEL_SANDYBRIDGE_S_HB 0x0108 /* Server */ #define PCI_DEVICE_ID_INTEL_SANDYBRIDGE_S_IG 0x010A -/* cover 915 and 945 variants */ -#define IS_I915 (agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_E7221_HB || \ - agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_82915G_HB || \ - agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_82915GM_HB || \ - agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_82945G_HB || \ - agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_82945GM_HB || \ - agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_82945GME_HB) - -#define IS_I965 (agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_82946GZ_HB || \ - agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_82G35_HB || \ - agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_82965Q_HB || \ - agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_82965G_HB || \ - agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_82965GM_HB || \ - agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_82965GME_HB) - -#define IS_G33 (agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_G33_HB || \ - agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_Q35_HB || \ - agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_Q33_HB || \ - agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_PINEVIEW_M_HB || \ - agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_PINEVIEW_HB) - -#define IS_PINEVIEW (agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_PINEVIEW_M_HB || \ - agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_PINEVIEW_HB) - -#define IS_SNB (agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_SANDYBRIDGE_HB || \ - agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_SANDYBRIDGE_M_HB || \ - agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_SANDYBRIDGE_S_HB) - -#define IS_G4X (agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_EAGLELAKE_HB || \ - agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_Q45_HB || \ - agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_G45_HB || \ - agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_GM45_HB || \ - agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_G41_HB || \ - agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_B43_HB || \ - agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_IRONLAKE_D_HB || \ - agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_IRONLAKE_M_HB || \ - agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_IRONLAKE_MA_HB || \ - agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_IRONLAKE_MC2_HB || \ - IS_SNB) - int intel_gmch_probe(struct pci_dev *pdev, struct agp_bridge_data *bridge); void intel_gmch_remove(struct pci_dev *pdev); diff --git a/drivers/char/agp/intel-gtt.c b/drivers/char/agp/intel-gtt.c index 3b84d84..831f3c5 100644 --- a/drivers/char/agp/intel-gtt.c +++ b/drivers/char/agp/intel-gtt.c @@ -81,8 +81,16 @@ static struct gatt_mask intel_gen6_masks[] = .type = INTEL_AGP_CACHED_MEMORY_LLC_MLC_GFDT }, }; +struct intel_gtt_driver { + unsigned int gen : 8; + unsigned int is_g33 : 1; + unsigned int is_pineview : 1; + unsigned int is_ironlake : 1; +}; + static struct _intel_private { struct intel_gtt base; + const struct intel_gtt_driver *driver; struct pci_dev *pcidev; /* device one */ struct pci_dev *bridge_dev; u8 __iomem *registers; @@ -97,6 +105,11 @@ static struct _intel_private { int resource_valid; } intel_private; +#define INTEL_GTT_GEN intel_private.driver->gen +#define IS_G33 intel_private.driver->is_g33 +#define IS_PINEVIEW intel_private.driver->is_pineview +#define IS_IRONLAKE intel_private.driver->is_ironlake + #ifdef USE_PCI_DMA_API static int intel_agp_map_page(struct page *page, dma_addr_t *ret) { @@ -543,7 +556,7 @@ static unsigned int intel_gtt_stolen_entries(void) pci_read_config_word(intel_private.bridge_dev, I830_GMCH_CTRL, &gmch_ctrl); - if (IS_G4X || IS_PINEVIEW) + if (INTEL_GTT_GEN > 4 || IS_PINEVIEW) overhead_entries = 0; else overhead_entries = intel_private.base.gtt_mappable_entries @@ -573,7 +586,7 @@ static unsigned int intel_gtt_stolen_entries(void) stolen_size = 0; break; } - } else if (IS_SNB) { + } else if (INTEL_GTT_GEN == 6) { /* * SandyBridge has new memory control reg at 0x50.w */ @@ -700,7 +713,7 @@ static unsigned int intel_gtt_total_entries(void) { int size; - if (IS_G33 || IS_I965 || IS_G4X) { + if (IS_G33 || INTEL_GTT_GEN >= 4) { u32 pgetbl_ctl; pgetbl_ctl = readl(intel_private.registers+I810_PGETBL_CTL); @@ -1086,7 +1099,7 @@ static void intel_i9xx_setup_flush(void) if (intel_private.ifp_resource.start) return; - if (IS_SNB) + if (INTEL_GTT_GEN == 6) return; /* setup a resource for this object */ @@ -1094,7 +1107,7 @@ static void intel_i9xx_setup_flush(void) intel_private.ifp_resource.flags = IORESOURCE_MEM; /* Setup chipset flush for 915 */ - if (IS_I965 || IS_G33 || IS_G4X) { + if (IS_G33 || INTEL_GTT_GEN >= 4) { intel_i965_g33_setup_chipset_flush(); } else { intel_i915_setup_chipset_flush(); @@ -1196,7 +1209,8 @@ static int intel_i915_insert_entries(struct agp_memory *mem, off_t pg_start, mask_type = agp_bridge->driver->agp_type_to_mask_type(agp_bridge, type); - if (!IS_SNB && mask_type != 0 && mask_type != AGP_PHYS_MEMORY && + if (INTEL_GTT_GEN != 6 && mask_type != 0 && + mask_type != AGP_PHYS_MEMORY && mask_type != INTEL_AGP_CACHED_MEMORY) goto out_err; @@ -1631,6 +1645,34 @@ static const struct agp_bridge_driver intel_g33_driver = { #endif }; +static const struct intel_gtt_driver i8xx_gtt_driver = { + .gen = 2, +}; +static const struct intel_gtt_driver i915_gtt_driver = { + .gen = 3, +}; +static const struct intel_gtt_driver g33_gtt_driver = { + .gen = 3, + .is_g33 = 1, +}; +static const struct intel_gtt_driver pineview_gtt_driver = { + .gen = 3, + .is_pineview = 1, .is_g33 = 1, +}; +static const struct intel_gtt_driver i965_gtt_driver = { + .gen = 4, +}; +static const struct intel_gtt_driver g4x_gtt_driver = { + .gen = 5, +}; +static const struct intel_gtt_driver ironlake_gtt_driver = { + .gen = 5, + .is_ironlake = 1, +}; +static const struct intel_gtt_driver sandybridge_gtt_driver = { + .gen = 6, +}; + /* Table to describe Intel GMCH and AGP/PCIE GART drivers. At least one of * driver and gmch_driver must be non-null, and find_gmch will determine * which one should be used if a gmch_chip_id is present. @@ -1639,57 +1681,86 @@ static const struct intel_gtt_driver_description { unsigned int gmch_chip_id; char *name; const struct agp_bridge_driver *gmch_driver; + const struct intel_gtt_driver *gtt_driver; } intel_gtt_chipsets[] = { - { PCI_DEVICE_ID_INTEL_82810_IG1, "i810", &intel_810_driver }, - { PCI_DEVICE_ID_INTEL_82810_IG3, "i810", &intel_810_driver }, - { PCI_DEVICE_ID_INTEL_82810E_IG, "i810", &intel_810_driver }, - { PCI_DEVICE_ID_INTEL_82815_CGC, "i815", &intel_810_driver }, - { PCI_DEVICE_ID_INTEL_82830_CGC, "830M", &intel_830_driver }, - { PCI_DEVICE_ID_INTEL_82845G_IG, "830M", &intel_830_driver }, - { PCI_DEVICE_ID_INTEL_82854_IG, "854", &intel_830_driver }, - { PCI_DEVICE_ID_INTEL_82855GM_IG, "855GM", &intel_830_driver }, - { PCI_DEVICE_ID_INTEL_82865_IG, "865", &intel_830_driver }, - { PCI_DEVICE_ID_INTEL_E7221_IG, "E7221 (i915)", &intel_915_driver }, - { PCI_DEVICE_ID_INTEL_82915G_IG, "915G", &intel_915_driver }, - { PCI_DEVICE_ID_INTEL_82915GM_IG, "915GM", &intel_915_driver }, - { PCI_DEVICE_ID_INTEL_82945G_IG, "945G", &intel_915_driver }, - { PCI_DEVICE_ID_INTEL_82945GM_IG, "945GM", &intel_915_driver }, - { PCI_DEVICE_ID_INTEL_82945GME_IG, "945GME", &intel_915_driver }, - { PCI_DEVICE_ID_INTEL_82946GZ_IG, "946GZ", &intel_i965_driver }, - { PCI_DEVICE_ID_INTEL_82G35_IG, "G35", &intel_i965_driver }, - { PCI_DEVICE_ID_INTEL_82965Q_IG, "965Q", &intel_i965_driver }, - { PCI_DEVICE_ID_INTEL_82965G_IG, "965G", &intel_i965_driver }, - { PCI_DEVICE_ID_INTEL_82965GM_IG, "965GM", &intel_i965_driver }, - { PCI_DEVICE_ID_INTEL_82965GME_IG, "965GME/GLE", &intel_i965_driver }, - { PCI_DEVICE_ID_INTEL_G33_IG, "G33", &intel_g33_driver }, - { PCI_DEVICE_ID_INTEL_Q35_IG, "Q35", &intel_g33_driver }, - { PCI_DEVICE_ID_INTEL_Q33_IG, "Q33", &intel_g33_driver }, - { PCI_DEVICE_ID_INTEL_PINEVIEW_M_IG, "GMA3150", &intel_g33_driver }, - { PCI_DEVICE_ID_INTEL_PINEVIEW_IG, "GMA3150", &intel_g33_driver }, - { PCI_DEVICE_ID_INTEL_GM45_IG, "GM45", &intel_i965_driver }, - { PCI_DEVICE_ID_INTEL_EAGLELAKE_IG, "Eaglelake", &intel_i965_driver }, - { PCI_DEVICE_ID_INTEL_Q45_IG, "Q45/Q43", &intel_i965_driver }, - { PCI_DEVICE_ID_INTEL_G45_IG, "G45/G43", &intel_i965_driver }, - { PCI_DEVICE_ID_INTEL_B43_IG, "B43", &intel_i965_driver }, - { PCI_DEVICE_ID_INTEL_G41_IG, "G41", &intel_i965_driver }, + { PCI_DEVICE_ID_INTEL_82810_IG1, "i810", &intel_810_driver , NULL}, + { PCI_DEVICE_ID_INTEL_82810_IG3, "i810", &intel_810_driver , NULL}, + { PCI_DEVICE_ID_INTEL_82810E_IG, "i810", &intel_810_driver , NULL}, + { PCI_DEVICE_ID_INTEL_82815_CGC, "i815", &intel_810_driver , NULL}, + { PCI_DEVICE_ID_INTEL_82830_CGC, "830M", + &intel_830_driver , &i8xx_gtt_driver}, + { PCI_DEVICE_ID_INTEL_82845G_IG, "830M", + &intel_830_driver , &i8xx_gtt_driver}, + { PCI_DEVICE_ID_INTEL_82854_IG, "854", + &intel_830_driver , &i8xx_gtt_driver}, + { PCI_DEVICE_ID_INTEL_82855GM_IG, "855GM", + &intel_830_driver , &i8xx_gtt_driver}, + { PCI_DEVICE_ID_INTEL_82865_IG, "865", + &intel_830_driver , &i8xx_gtt_driver}, + { PCI_DEVICE_ID_INTEL_E7221_IG, "E7221 (i915)", + &intel_915_driver , &i915_gtt_driver }, + { PCI_DEVICE_ID_INTEL_82915G_IG, "915G", + &intel_915_driver , &i915_gtt_driver }, + { PCI_DEVICE_ID_INTEL_82915GM_IG, "915GM", + &intel_915_driver , &i915_gtt_driver }, + { PCI_DEVICE_ID_INTEL_82945G_IG, "945G", + &intel_915_driver , &i915_gtt_driver }, + { PCI_DEVICE_ID_INTEL_82945GM_IG, "945GM", + &intel_915_driver , &i915_gtt_driver }, + { PCI_DEVICE_ID_INTEL_82945GME_IG, "945GME", + &intel_915_driver , &i915_gtt_driver }, + { PCI_DEVICE_ID_INTEL_82946GZ_IG, "946GZ", + &intel_i965_driver , &i965_gtt_driver }, + { PCI_DEVICE_ID_INTEL_82G35_IG, "G35", + &intel_i965_driver , &i965_gtt_driver }, + { PCI_DEVICE_ID_INTEL_82965Q_IG, "965Q", + &intel_i965_driver , &i965_gtt_driver }, + { PCI_DEVICE_ID_INTEL_82965G_IG, "965G", + &intel_i965_driver , &i965_gtt_driver }, + { PCI_DEVICE_ID_INTEL_82965GM_IG, "965GM", + &intel_i965_driver , &i965_gtt_driver }, + { PCI_DEVICE_ID_INTEL_82965GME_IG, "965GME/GLE", + &intel_i965_driver , &i965_gtt_driver }, + { PCI_DEVICE_ID_INTEL_G33_IG, "G33", + &intel_g33_driver , &g33_gtt_driver }, + { PCI_DEVICE_ID_INTEL_Q35_IG, "Q35", + &intel_g33_driver , &g33_gtt_driver }, + { PCI_DEVICE_ID_INTEL_Q33_IG, "Q33", + &intel_g33_driver , &g33_gtt_driver }, + { PCI_DEVICE_ID_INTEL_PINEVIEW_M_IG, "GMA3150", + &intel_g33_driver , &pineview_gtt_driver }, + { PCI_DEVICE_ID_INTEL_PINEVIEW_IG, "GMA3150", + &intel_g33_driver , &pineview_gtt_driver }, + { PCI_DEVICE_ID_INTEL_GM45_IG, "GM45", + &intel_i965_driver , &g4x_gtt_driver }, + { PCI_DEVICE_ID_INTEL_EAGLELAKE_IG, "Eaglelake", + &intel_i965_driver , &g4x_gtt_driver }, + { PCI_DEVICE_ID_INTEL_Q45_IG, "Q45/Q43", + &intel_i965_driver , &g4x_gtt_driver }, + { PCI_DEVICE_ID_INTEL_G45_IG, "G45/G43", + &intel_i965_driver , &g4x_gtt_driver }, + { PCI_DEVICE_ID_INTEL_B43_IG, "B43", + &intel_i965_driver , &g4x_gtt_driver }, + { PCI_DEVICE_ID_INTEL_G41_IG, "G41", + &intel_i965_driver , &g4x_gtt_driver }, { PCI_DEVICE_ID_INTEL_IRONLAKE_D_IG, - "HD Graphics", &intel_i965_driver }, + "HD Graphics", &intel_i965_driver , &ironlake_gtt_driver }, { PCI_DEVICE_ID_INTEL_IRONLAKE_M_IG, - "HD Graphics", &intel_i965_driver }, + "HD Graphics", &intel_i965_driver , &ironlake_gtt_driver }, { PCI_DEVICE_ID_INTEL_SANDYBRIDGE_GT1_IG, - "Sandybridge", &intel_gen6_driver }, + "Sandybridge", &intel_gen6_driver , &sandybridge_gtt_driver }, { PCI_DEVICE_ID_INTEL_SANDYBRIDGE_GT2_IG, - "Sandybridge", &intel_gen6_driver }, + "Sandybridge", &intel_gen6_driver , &sandybridge_gtt_driver }, { PCI_DEVICE_ID_INTEL_SANDYBRIDGE_GT2_PLUS_IG, - "Sandybridge", &intel_gen6_driver }, + "Sandybridge", &intel_gen6_driver , &sandybridge_gtt_driver }, { PCI_DEVICE_ID_INTEL_SANDYBRIDGE_M_GT1_IG, - "Sandybridge", &intel_gen6_driver }, + "Sandybridge", &intel_gen6_driver , &sandybridge_gtt_driver }, { PCI_DEVICE_ID_INTEL_SANDYBRIDGE_M_GT2_IG, - "Sandybridge", &intel_gen6_driver }, + "Sandybridge", &intel_gen6_driver , &sandybridge_gtt_driver }, { PCI_DEVICE_ID_INTEL_SANDYBRIDGE_M_GT2_PLUS_IG, - "Sandybridge", &intel_gen6_driver }, + "Sandybridge", &intel_gen6_driver , &sandybridge_gtt_driver }, { PCI_DEVICE_ID_INTEL_SANDYBRIDGE_S_IG, - "Sandybridge", &intel_gen6_driver }, + "Sandybridge", &intel_gen6_driver , &sandybridge_gtt_driver }, { 0, NULL, NULL } }; @@ -1720,6 +1791,8 @@ int intel_gmch_probe(struct pci_dev *pdev, if (find_gmch(intel_gtt_chipsets[i].gmch_chip_id)) { bridge->driver = intel_gtt_chipsets[i].gmch_driver; + intel_private.driver = + intel_gtt_chipsets[i].gtt_driver; break; } } -- cgit v1.1 From ccc4e67be5ac1bd38c4bfd61aca38366597e8afb Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Wed, 8 Sep 2010 21:20:12 +0200 Subject: intel-gtt: i915: use detected gtt size for mapping Slight reordering of the init sequence required. Signed-off-by: Daniel Vetter Signed-off-by: Chris Wilson --- drivers/char/agp/intel-gtt.c | 58 ++++++-------------------------------------- 1 file changed, 8 insertions(+), 50 deletions(-) diff --git a/drivers/char/agp/intel-gtt.c b/drivers/char/agp/intel-gtt.c index 831f3c5..3d93cd0 100644 --- a/drivers/char/agp/intel-gtt.c +++ b/drivers/char/agp/intel-gtt.c @@ -708,7 +708,6 @@ static unsigned int intel_gtt_stolen_entries(void) return stolen_entries; } -#if 0 /* extracted code in bad shape, needs some cleaning before use */ static unsigned int intel_gtt_total_entries(void) { int size; @@ -750,7 +749,6 @@ static unsigned int intel_gtt_total_entries(void) return intel_private.base.gtt_mappable_entries; } } -#endif static unsigned int intel_gtt_mappable_entries(void) { @@ -1248,45 +1246,6 @@ static int intel_i915_remove_entries(struct agp_memory *mem, off_t pg_start, return 0; } -/* Return the aperture size by just checking the resource length. The effect - * described in the spec of the MSAC registers is just changing of the - * resource size. - */ -static int intel_i915_get_gtt_size(void) -{ - int size; - - if (IS_G33) { - u16 gmch_ctrl; - - /* G33's GTT size defined in gmch_ctrl */ - pci_read_config_word(intel_private.bridge_dev, I830_GMCH_CTRL, &gmch_ctrl); - switch (gmch_ctrl & I830_GMCH_GMS_MASK) { - case I830_GMCH_GMS_STOLEN_512: - size = 512; - break; - case I830_GMCH_GMS_STOLEN_1024: - size = 1024; - break; - case I830_GMCH_GMS_STOLEN_8192: - size = 8*1024; - break; - default: - dev_info(&intel_private.bridge_dev->dev, - "unknown page table size 0x%x, assuming 512KB\n", - (gmch_ctrl & I830_GMCH_GMS_MASK)); - size = 512; - } - } else { - /* On previous hardware, the GTT size was just what was - * required to map the aperture. - */ - size = agp_bridge->driver->fetch_size(); - } - - return KB(size); -} - /* The intel i915 automatically initializes the agp aperture during POST. * Use the memory already set aside for in the GTT. */ @@ -1306,19 +1265,18 @@ static int intel_i915_create_gatt_table(struct agp_bridge_data *bridge) pci_read_config_dword(intel_private.pcidev, I915_MMADDR, &temp); pci_read_config_dword(intel_private.pcidev, I915_PTEADDR, &temp2); - gtt_map_size = intel_i915_get_gtt_size(); + temp &= 0xfff80000; - intel_private.gtt = ioremap(temp2, gtt_map_size); - if (!intel_private.gtt) + intel_private.registers = ioremap(temp, 128 * 4096); + if (!intel_private.registers) return -ENOMEM; - intel_private.base.gtt_total_entries = gtt_map_size / 4; - - temp &= 0xfff80000; + intel_private.base.gtt_total_entries = intel_gtt_total_entries(); + gtt_map_size = intel_private.base.gtt_total_entries * 4; - intel_private.registers = ioremap(temp, 128 * 4096); - if (!intel_private.registers) { - iounmap(intel_private.gtt); + intel_private.gtt = ioremap(temp2, gtt_map_size); + if (!intel_private.gtt) { + iounmap(intel_private.registers); return -ENOMEM; } -- cgit v1.1 From 210b23c2f7b9721afb0a57459b7dbac3b094862e Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Sat, 28 Aug 2010 16:14:32 +0200 Subject: intel-gtt: i965: use detected gtt size for mapping Also move the Sandybdridge size detection into gtt_total_entries, like the rest. Signed-off-by: Daniel Vetter Signed-off-by: Chris Wilson --- drivers/char/agp/intel-gtt.c | 76 ++++++++++++++++++++------------------------ 1 file changed, 34 insertions(+), 42 deletions(-) diff --git a/drivers/char/agp/intel-gtt.c b/drivers/char/agp/intel-gtt.c index 3d93cd0..cd0fd14 100644 --- a/drivers/char/agp/intel-gtt.c +++ b/drivers/char/agp/intel-gtt.c @@ -712,7 +712,7 @@ static unsigned int intel_gtt_total_entries(void) { int size; - if (IS_G33 || INTEL_GTT_GEN >= 4) { + if (IS_G33 || INTEL_GTT_GEN == 4 || INTEL_GTT_GEN == 5) { u32 pgetbl_ctl; pgetbl_ctl = readl(intel_private.registers+I810_PGETBL_CTL); @@ -742,6 +742,24 @@ static unsigned int intel_gtt_total_entries(void) } return size/4; + } else if (INTEL_GTT_GEN == 6) { + u16 snb_gmch_ctl; + + pci_read_config_word(intel_private.pcidev, SNB_GMCH_CTRL, &snb_gmch_ctl); + switch (snb_gmch_ctl & SNB_GTT_SIZE_MASK) { + default: + case SNB_GTT_SIZE_0M: + printk(KERN_ERR "Bad GTT size mask: 0x%04x.\n", snb_gmch_ctl); + size = MB(0); + break; + case SNB_GTT_SIZE_1M: + size = MB(1); + break; + case SNB_GTT_SIZE_2M: + size = MB(2); + break; + } + return size/4; } else { /* On previous hardware, the GTT size was just what was * required to map the aperture. @@ -1327,44 +1345,18 @@ static unsigned long intel_gen6_mask_memory(struct agp_bridge_data *bridge, static void intel_i965_get_gtt_range(int *gtt_offset, int *gtt_size) { - u16 snb_gmch_ctl; - - switch (intel_private.bridge_dev->device) { - case PCI_DEVICE_ID_INTEL_GM45_HB: - case PCI_DEVICE_ID_INTEL_EAGLELAKE_HB: - case PCI_DEVICE_ID_INTEL_Q45_HB: - case PCI_DEVICE_ID_INTEL_G45_HB: - case PCI_DEVICE_ID_INTEL_G41_HB: - case PCI_DEVICE_ID_INTEL_B43_HB: - case PCI_DEVICE_ID_INTEL_IRONLAKE_D_HB: - case PCI_DEVICE_ID_INTEL_IRONLAKE_M_HB: - case PCI_DEVICE_ID_INTEL_IRONLAKE_MA_HB: - case PCI_DEVICE_ID_INTEL_IRONLAKE_MC2_HB: - *gtt_offset = *gtt_size = MB(2); - break; - case PCI_DEVICE_ID_INTEL_SANDYBRIDGE_HB: - case PCI_DEVICE_ID_INTEL_SANDYBRIDGE_M_HB: - case PCI_DEVICE_ID_INTEL_SANDYBRIDGE_S_HB: + switch (INTEL_GTT_GEN) { + case 5: + case 6: *gtt_offset = MB(2); - - pci_read_config_word(intel_private.pcidev, SNB_GMCH_CTRL, &snb_gmch_ctl); - switch (snb_gmch_ctl & SNB_GTT_SIZE_MASK) { - default: - case SNB_GTT_SIZE_0M: - printk(KERN_ERR "Bad GTT size mask: 0x%04x.\n", snb_gmch_ctl); - *gtt_size = MB(0); - break; - case SNB_GTT_SIZE_1M: - *gtt_size = MB(1); - break; - case SNB_GTT_SIZE_2M: - *gtt_size = MB(2); - break; - } break; + case 4: default: - *gtt_offset = *gtt_size = KB(512); + *gtt_offset = KB(512); + break; } + + *gtt_size = intel_private.base.gtt_total_entries * 4; } /* The intel i965 automatically initializes the agp aperture during POST. @@ -1387,17 +1379,17 @@ static int intel_i965_create_gatt_table(struct agp_bridge_data *bridge) temp &= 0xfff00000; - intel_i965_get_gtt_range(>t_offset, >t_size); + intel_private.registers = ioremap(temp, 128 * 4096); + if (!intel_private.registers) + return -ENOMEM; - intel_private.gtt = ioremap((temp + gtt_offset) , gtt_size); + intel_private.base.gtt_total_entries = intel_gtt_total_entries(); - if (!intel_private.gtt) - return -ENOMEM; + intel_i965_get_gtt_range(>t_offset, >t_size); - intel_private.base.gtt_total_entries = gtt_size / 4; + intel_private.gtt = ioremap((temp + gtt_offset) , gtt_size); - intel_private.registers = ioremap(temp, 128 * 4096); - if (!intel_private.registers) { + if (!intel_private.gtt) { iounmap(intel_private.gtt); return -ENOMEM; } -- cgit v1.1 From fdfb58a965486d2afea4ef0f9b8153dab9b98b2e Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Sun, 29 Aug 2010 00:15:03 +0200 Subject: intel-gtt: i830: adjust ioremap of regs and gtt to i9xx This way around this can be extracted into common code. Also use a common cleanup function (and give it a generic name). Signed-off-by: Daniel Vetter Signed-off-by: Chris Wilson --- drivers/char/agp/intel-gtt.c | 41 +++++++++++++++++++++++------------------ 1 file changed, 23 insertions(+), 18 deletions(-) diff --git a/drivers/char/agp/intel-gtt.c b/drivers/char/agp/intel-gtt.c index cd0fd14..7359fbe 100644 --- a/drivers/char/agp/intel-gtt.c +++ b/drivers/char/agp/intel-gtt.c @@ -883,6 +883,7 @@ static int intel_i830_create_gatt_table(struct agp_bridge_data *bridge) int page_order, ret; struct aper_size_info_fixed *size; int num_entries; + int gtt_map_size; u32 temp; size = agp_bridge->current_size; @@ -893,10 +894,19 @@ static int intel_i830_create_gatt_table(struct agp_bridge_data *bridge) pci_read_config_dword(intel_private.pcidev, I810_MMADDR, &temp); temp &= 0xfff80000; - intel_private.registers = ioremap(temp, 128 * 4096); + intel_private.registers = ioremap(temp, KB(64)); if (!intel_private.registers) return -ENOMEM; + intel_private.base.gtt_total_entries = intel_gtt_total_entries(); + gtt_map_size = intel_private.base.gtt_total_entries * 4; + + intel_private.gtt = ioremap(temp + I810_PTE_BASE, gtt_map_size); + if (!intel_private.gtt) { + iounmap(intel_private.registers); + return -ENOMEM; + } + temp = readl(intel_private.registers+I810_PGETBL_CTL) & 0xfffff000; global_cache_flush(); /* FIXME: ?? */ @@ -940,9 +950,9 @@ static int intel_i830_configure(void) if (agp_bridge->driver->needs_scratch_page) { for (i = intel_private.base.gtt_stolen_entries; i < current_size->num_entries; i++) { - writel(agp_bridge->scratch_page, intel_private.registers+I810_PTE_BASE+(i*4)); + writel(agp_bridge->scratch_page, intel_private.gtt+i); } - readl(intel_private.registers+I810_PTE_BASE+((i-1)*4)); /* PCI Posting. */ + readl(intel_private.gtt+i-1); /* PCI Posting. */ } global_cache_flush(); @@ -951,11 +961,6 @@ static int intel_i830_configure(void) return 0; } -static void intel_i830_cleanup(void) -{ - iounmap(intel_private.registers); -} - static int intel_i830_insert_entries(struct agp_memory *mem, off_t pg_start, int type) { @@ -1002,9 +1007,9 @@ static int intel_i830_insert_entries(struct agp_memory *mem, off_t pg_start, for (i = 0, j = pg_start; i < mem->page_count; i++, j++) { writel(agp_bridge->driver->mask_memory(agp_bridge, page_to_phys(mem->pages[i]), mask_type), - intel_private.registers+I810_PTE_BASE+(j*4)); + intel_private.gtt+j); } - readl(intel_private.registers+I810_PTE_BASE+((j-1)*4)); + readl(intel_private.gtt+j-1); out: ret = 0; @@ -1028,9 +1033,9 @@ static int intel_i830_remove_entries(struct agp_memory *mem, off_t pg_start, } for (i = pg_start; i < (mem->page_count + pg_start); i++) { - writel(agp_bridge->scratch_page, intel_private.registers+I810_PTE_BASE+(i*4)); + writel(agp_bridge->scratch_page, intel_private.gtt+i); } - readl(intel_private.registers+I810_PTE_BASE+((i-1)*4)); + readl(intel_private.gtt+i-1); return 0; } @@ -1171,7 +1176,7 @@ static int intel_i9xx_configure(void) return 0; } -static void intel_i915_cleanup(void) +static void intel_gtt_cleanup(void) { if (intel_private.i9xx_flush_page) iounmap(intel_private.i9xx_flush_page); @@ -1444,7 +1449,7 @@ static const struct agp_bridge_driver intel_830_driver = { .needs_scratch_page = true, .configure = intel_i830_configure, .fetch_size = intel_fake_agp_fetch_size, - .cleanup = intel_i830_cleanup, + .cleanup = intel_gtt_cleanup, .mask_memory = intel_i810_mask_memory, .masks = intel_i810_masks, .agp_enable = intel_fake_agp_enable, @@ -1471,7 +1476,7 @@ static const struct agp_bridge_driver intel_915_driver = { .needs_scratch_page = true, .configure = intel_i9xx_configure, .fetch_size = intel_fake_agp_fetch_size, - .cleanup = intel_i915_cleanup, + .cleanup = intel_gtt_cleanup, .mask_memory = intel_i810_mask_memory, .masks = intel_i810_masks, .agp_enable = intel_fake_agp_enable, @@ -1504,7 +1509,7 @@ static const struct agp_bridge_driver intel_i965_driver = { .needs_scratch_page = true, .configure = intel_i9xx_configure, .fetch_size = intel_fake_agp_fetch_size, - .cleanup = intel_i915_cleanup, + .cleanup = intel_gtt_cleanup, .mask_memory = intel_i965_mask_memory, .masks = intel_i810_masks, .agp_enable = intel_fake_agp_enable, @@ -1537,7 +1542,7 @@ static const struct agp_bridge_driver intel_gen6_driver = { .needs_scratch_page = true, .configure = intel_i9xx_configure, .fetch_size = intel_fake_agp_fetch_size, - .cleanup = intel_i915_cleanup, + .cleanup = intel_gtt_cleanup, .mask_memory = intel_gen6_mask_memory, .masks = intel_gen6_masks, .agp_enable = intel_fake_agp_enable, @@ -1570,7 +1575,7 @@ static const struct agp_bridge_driver intel_g33_driver = { .needs_scratch_page = true, .configure = intel_i9xx_configure, .fetch_size = intel_fake_agp_fetch_size, - .cleanup = intel_i915_cleanup, + .cleanup = intel_gtt_cleanup, .mask_memory = intel_i965_mask_memory, .masks = intel_i810_masks, .agp_enable = intel_fake_agp_enable, -- cgit v1.1 From f67eab664c47b261517b09812477de9a1780b426 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Sun, 29 Aug 2010 17:27:36 +0200 Subject: intel-gtt: consolidate the gtt ioremap calls Signed-off-by: Daniel Vetter Signed-off-by: Chris Wilson --- drivers/char/agp/intel-gtt.c | 70 ++++++++++++++++---------------------------- 1 file changed, 26 insertions(+), 44 deletions(-) diff --git a/drivers/char/agp/intel-gtt.c b/drivers/char/agp/intel-gtt.c index 7359fbe..73082ef 100644 --- a/drivers/char/agp/intel-gtt.c +++ b/drivers/char/agp/intel-gtt.c @@ -94,6 +94,7 @@ static struct _intel_private { struct pci_dev *pcidev; /* device one */ struct pci_dev *bridge_dev; u8 __iomem *registers; + phys_addr_t gtt_bus_addr; u32 __iomem *gtt; /* I915G */ int num_dcache_entries; union { @@ -799,10 +800,27 @@ static unsigned int intel_gtt_mappable_entries(void) static int intel_gtt_init(void) { + u32 gtt_map_size; + + intel_private.base.gtt_mappable_entries = intel_gtt_mappable_entries(); + intel_private.base.gtt_total_entries = intel_gtt_total_entries(); + + gtt_map_size = intel_private.base.gtt_total_entries * 4; + + intel_private.gtt = ioremap(intel_private.gtt_bus_addr, + gtt_map_size); + if (!intel_private.gtt) { + iounmap(intel_private.registers); + return -ENOMEM; + } + + global_cache_flush(); /* FIXME: ? */ + /* we have to call this as early as possible after the MMIO base address is known */ intel_private.base.gtt_stolen_entries = intel_gtt_stolen_entries(); if (intel_private.base.gtt_stolen_entries == 0) { iounmap(intel_private.registers); + iounmap(intel_private.gtt); return -ENOMEM; } @@ -883,7 +901,6 @@ static int intel_i830_create_gatt_table(struct agp_bridge_data *bridge) int page_order, ret; struct aper_size_info_fixed *size; int num_entries; - int gtt_map_size; u32 temp; size = agp_bridge->current_size; @@ -898,17 +915,8 @@ static int intel_i830_create_gatt_table(struct agp_bridge_data *bridge) if (!intel_private.registers) return -ENOMEM; - intel_private.base.gtt_total_entries = intel_gtt_total_entries(); - gtt_map_size = intel_private.base.gtt_total_entries * 4; - - intel_private.gtt = ioremap(temp + I810_PTE_BASE, gtt_map_size); - if (!intel_private.gtt) { - iounmap(intel_private.registers); - return -ENOMEM; - } - + intel_private.gtt_bus_addr = temp + I810_PTE_BASE; temp = readl(intel_private.registers+I810_PGETBL_CTL) & 0xfffff000; - global_cache_flush(); /* FIXME: ?? */ ret = intel_gtt_init(); if (ret != 0) @@ -1278,7 +1286,6 @@ static int intel_i915_create_gatt_table(struct agp_bridge_data *bridge) struct aper_size_info_fixed *size; int num_entries; u32 temp, temp2; - int gtt_map_size; size = agp_bridge->current_size; page_order = size->page_order; @@ -1294,23 +1301,12 @@ static int intel_i915_create_gatt_table(struct agp_bridge_data *bridge) if (!intel_private.registers) return -ENOMEM; - intel_private.base.gtt_total_entries = intel_gtt_total_entries(); - gtt_map_size = intel_private.base.gtt_total_entries * 4; - - intel_private.gtt = ioremap(temp2, gtt_map_size); - if (!intel_private.gtt) { - iounmap(intel_private.registers); - return -ENOMEM; - } - + intel_private.gtt_bus_addr = temp2; temp = readl(intel_private.registers+I810_PGETBL_CTL) & 0xfffff000; - global_cache_flush(); /* FIXME: ? */ ret = intel_gtt_init(); - if (ret != 0) { - iounmap(intel_private.gtt); + if (ret != 0) return ret; - } agp_bridge->gatt_table = NULL; @@ -1348,7 +1344,7 @@ static unsigned long intel_gen6_mask_memory(struct agp_bridge_data *bridge, return addr | bridge->driver->masks[type].mask; } -static void intel_i965_get_gtt_range(int *gtt_offset, int *gtt_size) +static void intel_i965_get_gtt_range(int *gtt_offset) { switch (INTEL_GTT_GEN) { case 5: @@ -1360,8 +1356,6 @@ static void intel_i965_get_gtt_range(int *gtt_offset, int *gtt_size) *gtt_offset = KB(512); break; } - - *gtt_size = intel_private.base.gtt_total_entries * 4; } /* The intel i965 automatically initializes the agp aperture during POST. @@ -1373,7 +1367,7 @@ static int intel_i965_create_gatt_table(struct agp_bridge_data *bridge) struct aper_size_info_fixed *size; int num_entries; u32 temp; - int gtt_offset, gtt_size; + int gtt_offset; size = agp_bridge->current_size; page_order = size->page_order; @@ -1388,25 +1382,13 @@ static int intel_i965_create_gatt_table(struct agp_bridge_data *bridge) if (!intel_private.registers) return -ENOMEM; - intel_private.base.gtt_total_entries = intel_gtt_total_entries(); - - intel_i965_get_gtt_range(>t_offset, >t_size); - - intel_private.gtt = ioremap((temp + gtt_offset) , gtt_size); - - if (!intel_private.gtt) { - iounmap(intel_private.gtt); - return -ENOMEM; - } - + intel_i965_get_gtt_range(>t_offset); + intel_private.gtt_bus_addr = temp + gtt_offset; temp = readl(intel_private.registers+I810_PGETBL_CTL) & 0xfffff000; - global_cache_flush(); /* FIXME: ? */ ret = intel_gtt_init(); - if (ret != 0) { - iounmap(intel_private.gtt); + if (ret != 0) return ret; - } agp_bridge->gatt_table = NULL; -- cgit v1.1 From 73800422a30e9b8b6e0e49c27af9e9d196e52fd9 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Sun, 29 Aug 2010 17:29:50 +0200 Subject: intel-gtt: consolidate i830 setup Slighlty reordered sequence was necessary. Also don't set agp_bridge->gatt_bus_addr anymore. Only used by generic agp helper functions, hence unnecessary for the intel fake agp driver. Signed-off-by: Daniel Vetter Signed-off-by: Chris Wilson --- drivers/char/agp/intel-gtt.c | 83 ++++++++++++++++++++++++++------------------ 1 file changed, 49 insertions(+), 34 deletions(-) diff --git a/drivers/char/agp/intel-gtt.c b/drivers/char/agp/intel-gtt.c index 73082ef..fd977aa4 100644 --- a/drivers/char/agp/intel-gtt.c +++ b/drivers/char/agp/intel-gtt.c @@ -86,6 +86,8 @@ struct intel_gtt_driver { unsigned int is_g33 : 1; unsigned int is_pineview : 1; unsigned int is_ironlake : 1; + /* Chipset specific GTT setup */ + int (*setup)(void); }; static struct _intel_private { @@ -95,6 +97,7 @@ static struct _intel_private { struct pci_dev *bridge_dev; u8 __iomem *registers; phys_addr_t gtt_bus_addr; + phys_addr_t gma_bus_addr; u32 __iomem *gtt; /* I915G */ int num_dcache_entries; union { @@ -893,38 +896,60 @@ static void intel_i830_chipset_flush(struct agp_bridge_data *bridge) printk(KERN_ERR "Timed out waiting for cache flush.\n"); } -/* The intel i830 automatically initializes the agp aperture during POST. - * Use the memory already set aside for in the GTT. - */ -static int intel_i830_create_gatt_table(struct agp_bridge_data *bridge) +static void intel_enable_gtt(void) { - int page_order, ret; - struct aper_size_info_fixed *size; - int num_entries; - u32 temp; + u32 ptetbl_addr, gma_addr; + u16 gmch_ctrl; - size = agp_bridge->current_size; - page_order = size->page_order; - num_entries = size->num_entries; - agp_bridge->gatt_table_real = NULL; + ptetbl_addr = readl(intel_private.registers+I810_PGETBL_CTL) & 0xfffff000; - pci_read_config_dword(intel_private.pcidev, I810_MMADDR, &temp); - temp &= 0xfff80000; + pci_read_config_dword(intel_private.pcidev, I810_GMADDR, &gma_addr); + intel_private.gma_bus_addr = (gma_addr & PCI_BASE_ADDRESS_MEM_MASK); - intel_private.registers = ioremap(temp, KB(64)); + pci_read_config_word(intel_private.bridge_dev, I830_GMCH_CTRL, &gmch_ctrl); + gmch_ctrl |= I830_GMCH_ENABLED; + pci_write_config_word(intel_private.bridge_dev, I830_GMCH_CTRL, gmch_ctrl); + + writel(ptetbl_addr|I810_PGETBL_ENABLED, intel_private.registers+I810_PGETBL_CTL); + readl(intel_private.registers+I810_PGETBL_CTL); /* PCI Posting. */ +} + +static int i830_setup(void) +{ + u32 reg_addr; + + pci_read_config_dword(intel_private.pcidev, I810_MMADDR, ®_addr); + reg_addr &= 0xfff80000; + + intel_private.registers = ioremap(reg_addr, KB(64)); if (!intel_private.registers) return -ENOMEM; - intel_private.gtt_bus_addr = temp + I810_PTE_BASE; - temp = readl(intel_private.registers+I810_PGETBL_CTL) & 0xfffff000; + intel_private.gtt_bus_addr = reg_addr + I810_PTE_BASE; + + intel_i830_setup_flush(); + + return 0; +} + +/* The intel i830 automatically initializes the agp aperture during POST. + * Use the memory already set aside for in the GTT. + */ +static int intel_i830_create_gatt_table(struct agp_bridge_data *bridge) +{ + int ret; + + ret = intel_private.driver->setup(); + if (ret != 0) + return ret; ret = intel_gtt_init(); if (ret != 0) return ret; + agp_bridge->gatt_table_real = NULL; agp_bridge->gatt_table = NULL; - - agp_bridge->gatt_bus_addr = temp; + agp_bridge->gatt_bus_addr = 0; return 0; } @@ -939,25 +964,15 @@ static int intel_fake_agp_free_gatt_table(struct agp_bridge_data *bridge) static int intel_i830_configure(void) { - struct aper_size_info_fixed *current_size; - u32 temp; - u16 gmch_ctrl; int i; - current_size = A_SIZE_FIX(agp_bridge->current_size); - - pci_read_config_dword(intel_private.pcidev, I810_GMADDR, &temp); - agp_bridge->gart_bus_addr = (temp & PCI_BASE_ADDRESS_MEM_MASK); - - pci_read_config_word(intel_private.bridge_dev, I830_GMCH_CTRL, &gmch_ctrl); - gmch_ctrl |= I830_GMCH_ENABLED; - pci_write_config_word(intel_private.bridge_dev, I830_GMCH_CTRL, gmch_ctrl); + intel_enable_gtt(); - writel(agp_bridge->gatt_bus_addr|I810_PGETBL_ENABLED, intel_private.registers+I810_PGETBL_CTL); - readl(intel_private.registers+I810_PGETBL_CTL); /* PCI Posting. */ + agp_bridge->gart_bus_addr = intel_private.gma_bus_addr; if (agp_bridge->driver->needs_scratch_page) { - for (i = intel_private.base.gtt_stolen_entries; i < current_size->num_entries; i++) { + for (i = intel_private.base.gtt_stolen_entries; + i < intel_private.base.gtt_total_entries; i++) { writel(agp_bridge->scratch_page, intel_private.gtt+i); } readl(intel_private.gtt+i-1); /* PCI Posting. */ @@ -965,7 +980,6 @@ static int intel_i830_configure(void) global_cache_flush(); - intel_i830_setup_flush(); return 0; } @@ -1584,6 +1598,7 @@ static const struct agp_bridge_driver intel_g33_driver = { static const struct intel_gtt_driver i8xx_gtt_driver = { .gen = 2, + .setup = i830_setup, }; static const struct intel_gtt_driver i915_gtt_driver = { .gen = 3, -- cgit v1.1 From 2d2430cf9bf9e8b0ad9ea34a103625f4fe7e4477 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Sun, 29 Aug 2010 17:35:30 +0200 Subject: intel-gtt: consolidate i9xx setup The only difference between i915 and i965 was the calculation of the gtt address. So merge these two paths into one. Otherwise the same changes as in the i830 setup consolidation. Signed-off-by: Daniel Vetter Signed-off-by: Chris Wilson --- drivers/char/agp/intel-gtt.c | 154 +++++++++++++++++-------------------------- 1 file changed, 61 insertions(+), 93 deletions(-) diff --git a/drivers/char/agp/intel-gtt.c b/drivers/char/agp/intel-gtt.c index fd977aa4..7ac7d5c 100644 --- a/drivers/char/agp/intel-gtt.c +++ b/drivers/char/agp/intel-gtt.c @@ -903,7 +903,13 @@ static void intel_enable_gtt(void) ptetbl_addr = readl(intel_private.registers+I810_PGETBL_CTL) & 0xfffff000; - pci_read_config_dword(intel_private.pcidev, I810_GMADDR, &gma_addr); + if (INTEL_GTT_GEN == 2) + pci_read_config_dword(intel_private.pcidev, I810_GMADDR, + &gma_addr); + else + pci_read_config_dword(intel_private.pcidev, I915_GMADDR, + &gma_addr); + intel_private.gma_bus_addr = (gma_addr & PCI_BASE_ADDRESS_MEM_MASK); pci_read_config_word(intel_private.bridge_dev, I830_GMCH_CTRL, &gmch_ctrl); @@ -1165,23 +1171,11 @@ static void intel_i9xx_setup_flush(void) static int intel_i9xx_configure(void) { - struct aper_size_info_fixed *current_size; - u32 temp; - u16 gmch_ctrl; int i; - current_size = A_SIZE_FIX(agp_bridge->current_size); - - pci_read_config_dword(intel_private.pcidev, I915_GMADDR, &temp); - - agp_bridge->gart_bus_addr = (temp & PCI_BASE_ADDRESS_MEM_MASK); - - pci_read_config_word(intel_private.bridge_dev, I830_GMCH_CTRL, &gmch_ctrl); - gmch_ctrl |= I830_GMCH_ENABLED; - pci_write_config_word(intel_private.bridge_dev, I830_GMCH_CTRL, gmch_ctrl); + intel_enable_gtt(); - writel(agp_bridge->gatt_bus_addr|I810_PGETBL_ENABLED, intel_private.registers+I810_PGETBL_CTL); - readl(intel_private.registers+I810_PGETBL_CTL); /* PCI Posting. */ + agp_bridge->gart_bus_addr = intel_private.gma_bus_addr; if (agp_bridge->driver->needs_scratch_page) { for (i = intel_private.base.gtt_stolen_entries; i < @@ -1193,8 +1187,6 @@ static int intel_i9xx_configure(void) global_cache_flush(); - intel_i9xx_setup_flush(); - return 0; } @@ -1291,40 +1283,62 @@ static int intel_i915_remove_entries(struct agp_memory *mem, off_t pg_start, return 0; } -/* The intel i915 automatically initializes the agp aperture during POST. - * Use the memory already set aside for in the GTT. - */ -static int intel_i915_create_gatt_table(struct agp_bridge_data *bridge) +static int i9xx_setup(void) { - int page_order, ret; - struct aper_size_info_fixed *size; - int num_entries; - u32 temp, temp2; - - size = agp_bridge->current_size; - page_order = size->page_order; - num_entries = size->num_entries; - agp_bridge->gatt_table_real = NULL; + u32 reg_addr; - pci_read_config_dword(intel_private.pcidev, I915_MMADDR, &temp); - pci_read_config_dword(intel_private.pcidev, I915_PTEADDR, &temp2); + pci_read_config_dword(intel_private.pcidev, I915_MMADDR, ®_addr); - temp &= 0xfff80000; + reg_addr &= 0xfff80000; - intel_private.registers = ioremap(temp, 128 * 4096); + intel_private.registers = ioremap(reg_addr, 128 * 4096); if (!intel_private.registers) return -ENOMEM; - intel_private.gtt_bus_addr = temp2; - temp = readl(intel_private.registers+I810_PGETBL_CTL) & 0xfffff000; + if (INTEL_GTT_GEN == 3) { + u32 gtt_addr; + pci_read_config_dword(intel_private.pcidev, + I915_PTEADDR, >t_addr); + intel_private.gtt_bus_addr = gtt_addr; + } else { + u32 gtt_offset; + + switch (INTEL_GTT_GEN) { + case 5: + case 6: + gtt_offset = MB(2); + break; + case 4: + default: + gtt_offset = KB(512); + break; + } + intel_private.gtt_bus_addr = reg_addr + gtt_offset; + } + + intel_i9xx_setup_flush(); + + return 0; +} + +/* The intel i915 automatically initializes the agp aperture during POST. + * Use the memory already set aside for in the GTT. + */ +static int intel_i915_create_gatt_table(struct agp_bridge_data *bridge) +{ + int ret; + + ret = intel_private.driver->setup(); + if (ret != 0) + return ret; ret = intel_gtt_init(); if (ret != 0) return ret; + agp_bridge->gatt_table_real = NULL; agp_bridge->gatt_table = NULL; - - agp_bridge->gatt_bus_addr = temp; + agp_bridge->gatt_bus_addr = 0; return 0; } @@ -1358,59 +1372,6 @@ static unsigned long intel_gen6_mask_memory(struct agp_bridge_data *bridge, return addr | bridge->driver->masks[type].mask; } -static void intel_i965_get_gtt_range(int *gtt_offset) -{ - switch (INTEL_GTT_GEN) { - case 5: - case 6: - *gtt_offset = MB(2); - break; - case 4: - default: - *gtt_offset = KB(512); - break; - } -} - -/* The intel i965 automatically initializes the agp aperture during POST. - * Use the memory already set aside for in the GTT. - */ -static int intel_i965_create_gatt_table(struct agp_bridge_data *bridge) -{ - int page_order, ret; - struct aper_size_info_fixed *size; - int num_entries; - u32 temp; - int gtt_offset; - - size = agp_bridge->current_size; - page_order = size->page_order; - num_entries = size->num_entries; - agp_bridge->gatt_table_real = NULL; - - pci_read_config_dword(intel_private.pcidev, I915_MMADDR, &temp); - - temp &= 0xfff00000; - - intel_private.registers = ioremap(temp, 128 * 4096); - if (!intel_private.registers) - return -ENOMEM; - - intel_i965_get_gtt_range(>t_offset); - intel_private.gtt_bus_addr = temp + gtt_offset; - temp = readl(intel_private.registers+I810_PGETBL_CTL) & 0xfffff000; - - ret = intel_gtt_init(); - if (ret != 0) - return ret; - - agp_bridge->gatt_table = NULL; - - agp_bridge->gatt_bus_addr = temp; - - return 0; -} - static const struct agp_bridge_driver intel_810_driver = { .owner = THIS_MODULE, .aperture_sizes = intel_i810_sizes, @@ -1510,7 +1471,7 @@ static const struct agp_bridge_driver intel_i965_driver = { .masks = intel_i810_masks, .agp_enable = intel_fake_agp_enable, .cache_flush = global_cache_flush, - .create_gatt_table = intel_i965_create_gatt_table, + .create_gatt_table = intel_i915_create_gatt_table, .free_gatt_table = intel_fake_agp_free_gatt_table, .insert_memory = intel_i915_insert_entries, .remove_memory = intel_i915_remove_entries, @@ -1543,7 +1504,7 @@ static const struct agp_bridge_driver intel_gen6_driver = { .masks = intel_gen6_masks, .agp_enable = intel_fake_agp_enable, .cache_flush = global_cache_flush, - .create_gatt_table = intel_i965_create_gatt_table, + .create_gatt_table = intel_i915_create_gatt_table, .free_gatt_table = intel_fake_agp_free_gatt_table, .insert_memory = intel_i915_insert_entries, .remove_memory = intel_i915_remove_entries, @@ -1602,27 +1563,34 @@ static const struct intel_gtt_driver i8xx_gtt_driver = { }; static const struct intel_gtt_driver i915_gtt_driver = { .gen = 3, + .setup = i9xx_setup, }; static const struct intel_gtt_driver g33_gtt_driver = { .gen = 3, .is_g33 = 1, + .setup = i9xx_setup, }; static const struct intel_gtt_driver pineview_gtt_driver = { .gen = 3, .is_pineview = 1, .is_g33 = 1, + .setup = i9xx_setup, }; static const struct intel_gtt_driver i965_gtt_driver = { .gen = 4, + .setup = i9xx_setup, }; static const struct intel_gtt_driver g4x_gtt_driver = { .gen = 5, + .setup = i9xx_setup, }; static const struct intel_gtt_driver ironlake_gtt_driver = { .gen = 5, .is_ironlake = 1, + .setup = i9xx_setup, }; static const struct intel_gtt_driver sandybridge_gtt_driver = { .gen = 6, + .setup = i9xx_setup, }; /* Table to describe Intel GMCH and AGP/PCIE GART drivers. At least one of -- cgit v1.1 From 3b15a9d7cd59b7ec79f61aafabfbe84116561461 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Sun, 29 Aug 2010 14:18:49 +0200 Subject: intel-gtt: call init_gtt_init in probe function This way create_gatt_table become dummy glue functions for the fake agp driver - rename them accordingly (and kill the now unnecessary i9xx copy). With this change, the gtt initialization code is almost independant from the agp stuff. Two things are still missing: - the scratch page is created by the generic agp code. - filling the whole gtt with scratch_page ptes is not yet consolidated - this needs abstracted pte handling, first. Signed-off-by: Daniel Vetter Signed-off-by: Chris Wilson --- drivers/char/agp/intel-gtt.c | 60 +++++++++++--------------------------------- 1 file changed, 15 insertions(+), 45 deletions(-) diff --git a/drivers/char/agp/intel-gtt.c b/drivers/char/agp/intel-gtt.c index 7ac7d5c..d7207e8 100644 --- a/drivers/char/agp/intel-gtt.c +++ b/drivers/char/agp/intel-gtt.c @@ -804,6 +804,13 @@ static unsigned int intel_gtt_mappable_entries(void) static int intel_gtt_init(void) { u32 gtt_map_size; + int ret; + + intel_private.base.gtt_mappable_entries = intel_gtt_mappable_entries(); + + ret = intel_private.driver->setup(); + if (ret != 0) + return ret; intel_private.base.gtt_mappable_entries = intel_gtt_mappable_entries(); intel_private.base.gtt_total_entries = intel_gtt_total_entries(); @@ -938,21 +945,8 @@ static int i830_setup(void) return 0; } -/* The intel i830 automatically initializes the agp aperture during POST. - * Use the memory already set aside for in the GTT. - */ -static int intel_i830_create_gatt_table(struct agp_bridge_data *bridge) +static int intel_fake_agp_create_gatt_table(struct agp_bridge_data *bridge) { - int ret; - - ret = intel_private.driver->setup(); - if (ret != 0) - return ret; - - ret = intel_gtt_init(); - if (ret != 0) - return ret; - agp_bridge->gatt_table_real = NULL; agp_bridge->gatt_table = NULL; agp_bridge->gatt_bus_addr = 0; @@ -960,9 +954,6 @@ static int intel_i830_create_gatt_table(struct agp_bridge_data *bridge) return 0; } -/* Return the gatt table to a sane state. Use the top of stolen - * memory for the GTT. - */ static int intel_fake_agp_free_gatt_table(struct agp_bridge_data *bridge) { return 0; @@ -1321,28 +1312,6 @@ static int i9xx_setup(void) return 0; } -/* The intel i915 automatically initializes the agp aperture during POST. - * Use the memory already set aside for in the GTT. - */ -static int intel_i915_create_gatt_table(struct agp_bridge_data *bridge) -{ - int ret; - - ret = intel_private.driver->setup(); - if (ret != 0) - return ret; - - ret = intel_gtt_init(); - if (ret != 0) - return ret; - - agp_bridge->gatt_table_real = NULL; - agp_bridge->gatt_table = NULL; - agp_bridge->gatt_bus_addr = 0; - - return 0; -} - /* * The i965 supports 36-bit physical addresses, but to keep * the format of the GTT the same, the bits that don't fit @@ -1411,7 +1380,7 @@ static const struct agp_bridge_driver intel_830_driver = { .masks = intel_i810_masks, .agp_enable = intel_fake_agp_enable, .cache_flush = global_cache_flush, - .create_gatt_table = intel_i830_create_gatt_table, + .create_gatt_table = intel_fake_agp_create_gatt_table, .free_gatt_table = intel_fake_agp_free_gatt_table, .insert_memory = intel_i830_insert_entries, .remove_memory = intel_i830_remove_entries, @@ -1438,7 +1407,7 @@ static const struct agp_bridge_driver intel_915_driver = { .masks = intel_i810_masks, .agp_enable = intel_fake_agp_enable, .cache_flush = global_cache_flush, - .create_gatt_table = intel_i915_create_gatt_table, + .create_gatt_table = intel_fake_agp_create_gatt_table, .free_gatt_table = intel_fake_agp_free_gatt_table, .insert_memory = intel_i915_insert_entries, .remove_memory = intel_i915_remove_entries, @@ -1471,7 +1440,7 @@ static const struct agp_bridge_driver intel_i965_driver = { .masks = intel_i810_masks, .agp_enable = intel_fake_agp_enable, .cache_flush = global_cache_flush, - .create_gatt_table = intel_i915_create_gatt_table, + .create_gatt_table = intel_fake_agp_create_gatt_table, .free_gatt_table = intel_fake_agp_free_gatt_table, .insert_memory = intel_i915_insert_entries, .remove_memory = intel_i915_remove_entries, @@ -1504,7 +1473,7 @@ static const struct agp_bridge_driver intel_gen6_driver = { .masks = intel_gen6_masks, .agp_enable = intel_fake_agp_enable, .cache_flush = global_cache_flush, - .create_gatt_table = intel_i915_create_gatt_table, + .create_gatt_table = intel_fake_agp_create_gatt_table, .free_gatt_table = intel_fake_agp_free_gatt_table, .insert_memory = intel_i915_insert_entries, .remove_memory = intel_i915_remove_entries, @@ -1537,7 +1506,7 @@ static const struct agp_bridge_driver intel_g33_driver = { .masks = intel_i810_masks, .agp_enable = intel_fake_agp_enable, .cache_flush = global_cache_flush, - .create_gatt_table = intel_i915_create_gatt_table, + .create_gatt_table = intel_fake_agp_create_gatt_table, .free_gatt_table = intel_fake_agp_free_gatt_table, .insert_memory = intel_i915_insert_entries, .remove_memory = intel_i915_remove_entries, @@ -1744,7 +1713,8 @@ int intel_gmch_probe(struct pci_dev *pdev, if (bridge->driver == &intel_810_driver) return 1; - intel_private.base.gtt_mappable_entries = intel_gtt_mappable_entries(); + if (intel_gtt_init() != 0) + return 0; return 1; } -- cgit v1.1 From 239918f7a5ac118ecfe9c55a4cfd25d7767b674a Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Tue, 31 Aug 2010 22:30:43 +0200 Subject: intel-gtt: use chipset generation number some more Signed-off-by: Daniel Vetter Signed-off-by: Chris Wilson --- drivers/char/agp/intel-gtt.c | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/drivers/char/agp/intel-gtt.c b/drivers/char/agp/intel-gtt.c index d7207e8..6eb64c1 100644 --- a/drivers/char/agp/intel-gtt.c +++ b/drivers/char/agp/intel-gtt.c @@ -782,20 +782,14 @@ static unsigned int intel_gtt_mappable_entries(void) pci_read_config_word(intel_private.bridge_dev, I830_GMCH_CTRL, &gmch_ctrl); - switch (intel_private.pcidev->device) { - case PCI_DEVICE_ID_INTEL_82830_CGC: - case PCI_DEVICE_ID_INTEL_82845G_IG: - case PCI_DEVICE_ID_INTEL_82855GM_IG: - case PCI_DEVICE_ID_INTEL_82865_IG: + if (INTEL_GTT_GEN == 2) { if ((gmch_ctrl & I830_GMCH_MEM_MASK) == I830_GMCH_MEM_64M) aperture_size *= 64; else aperture_size *= 128; - break; - default: + } else { /* 9xx supports large sizes, just look at the length */ aperture_size = pci_resource_len(intel_private.pcidev, 2); - break; } return aperture_size >> PAGE_SHIFT; -- cgit v1.1 From ac622a9cdb742cad90648d95f2c4877774518f19 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Wed, 8 Sep 2010 21:26:07 +0200 Subject: drm/i915: drop prealloc_start from i915_dma gtt init Not used and simply confusing. Signed-off-by: Daniel Vetter Signed-off-by: Chris Wilson --- drivers/gpu/drm/i915/i915_dma.c | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_dma.c b/drivers/gpu/drm/i915/i915_dma.c index 47228cb16..a693b27 100644 --- a/drivers/gpu/drm/i915/i915_dma.c +++ b/drivers/gpu/drm/i915/i915_dma.c @@ -1000,8 +1000,7 @@ intel_teardown_mchbar(struct drm_device *dev) * how much was set aside so we can use it for our own purposes. */ static int i915_probe_agp(struct drm_device *dev, uint32_t *aperture_size, - uint32_t *preallocated_size, - uint32_t *start) + uint32_t *preallocated_size) { struct drm_i915_private *dev_priv = dev->dev_private; u16 tmp = 0; @@ -1152,7 +1151,6 @@ static int i915_probe_agp(struct drm_device *dev, uint32_t *aperture_size, } *preallocated_size = stolen - overhead; - *start = overhead; return 0; } @@ -1362,7 +1360,6 @@ static bool i915_switcheroo_can_switch(struct pci_dev *pdev) } static int i915_load_modeset_init(struct drm_device *dev, - unsigned long prealloc_start, unsigned long prealloc_size, unsigned long agp_size) { @@ -2051,7 +2048,7 @@ int i915_driver_load(struct drm_device *dev, unsigned long flags) struct drm_i915_private *dev_priv; resource_size_t base, size; int ret = 0, mmio_bar; - uint32_t agp_size, prealloc_size, prealloc_start; + uint32_t agp_size, prealloc_size; /* i915 has 4 more counters */ dev->counters += 4; dev->types[6] = _DRM_STAT_IRQ; @@ -2110,7 +2107,7 @@ int i915_driver_load(struct drm_device *dev, unsigned long flags) "performance may suffer.\n"); } - ret = i915_probe_agp(dev, &agp_size, &prealloc_size, &prealloc_start); + ret = i915_probe_agp(dev, &agp_size, &prealloc_size); if (ret) goto out_iomapfree; @@ -2202,8 +2199,7 @@ int i915_driver_load(struct drm_device *dev, unsigned long flags) intel_detect_pch(dev); if (drm_core_check_feature(dev, DRIVER_MODESET)) { - ret = i915_load_modeset_init(dev, prealloc_start, - prealloc_size, agp_size); + ret = i915_load_modeset_init(dev, prealloc_size, agp_size); if (ret < 0) { DRM_ERROR("failed to init modeset\n"); goto out_workqueue_free; -- cgit v1.1 From 19966754328d99ee003ddfc7a8c31ceb115483ac Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Mon, 6 Sep 2010 20:08:44 +0200 Subject: drm/i915: die, i915_probe_agp, die Use the detection from intel-gtt.ko instead. Hooray! Also move the stolen mem allocator to the other gtt stuff in dev_prv->mem. v2: Chris Wilson noted that my error handling was crap. Fix it. He also said that this fixes a problem on his i845. Indeed, i915_probe_agp misses a special case for i830/i845 stolen mem detection. Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=25476 Cc: stable@kernel.org Signed-off-by: Daniel Vetter Signed-off-by: Chris Wilson --- drivers/char/agp/intel-gtt.c | 6 ++ drivers/gpu/drm/i915/i915_dma.c | 190 +++------------------------------------- drivers/gpu/drm/i915/i915_drv.h | 7 +- include/drm/intel-gtt.h | 2 + 4 files changed, 25 insertions(+), 180 deletions(-) diff --git a/drivers/char/agp/intel-gtt.c b/drivers/char/agp/intel-gtt.c index 6eb64c1..9cb7c98 100644 --- a/drivers/char/agp/intel-gtt.c +++ b/drivers/char/agp/intel-gtt.c @@ -1714,6 +1714,12 @@ int intel_gmch_probe(struct pci_dev *pdev, } EXPORT_SYMBOL(intel_gmch_probe); +struct intel_gtt *intel_gtt_get(void) +{ + return &intel_private.base; +} +EXPORT_SYMBOL(intel_gtt_get); + void intel_gmch_remove(struct pci_dev *pdev) { if (intel_private.pcidev) diff --git a/drivers/gpu/drm/i915/i915_dma.c b/drivers/gpu/drm/i915/i915_dma.c index a693b27..428c75b 100644 --- a/drivers/gpu/drm/i915/i915_dma.c +++ b/drivers/gpu/drm/i915/i915_dma.c @@ -989,172 +989,6 @@ intel_teardown_mchbar(struct drm_device *dev) release_resource(&dev_priv->mch_res); } -/** - * i915_probe_agp - get AGP bootup configuration - * @pdev: PCI device - * @aperture_size: returns AGP aperture configured size - * @preallocated_size: returns size of BIOS preallocated AGP space - * - * Since Intel integrated graphics are UMA, the BIOS has to set aside - * some RAM for the framebuffer at early boot. This code figures out - * how much was set aside so we can use it for our own purposes. - */ -static int i915_probe_agp(struct drm_device *dev, uint32_t *aperture_size, - uint32_t *preallocated_size) -{ - struct drm_i915_private *dev_priv = dev->dev_private; - u16 tmp = 0; - unsigned long overhead; - unsigned long stolen; - - /* Get the fb aperture size and "stolen" memory amount. */ - pci_read_config_word(dev_priv->bridge_dev, INTEL_GMCH_CTRL, &tmp); - - *aperture_size = 1024 * 1024; - *preallocated_size = 1024 * 1024; - - switch (dev->pdev->device) { - case PCI_DEVICE_ID_INTEL_82830_CGC: - case PCI_DEVICE_ID_INTEL_82845G_IG: - case PCI_DEVICE_ID_INTEL_82855GM_IG: - case PCI_DEVICE_ID_INTEL_82865_IG: - if ((tmp & INTEL_GMCH_MEM_MASK) == INTEL_GMCH_MEM_64M) - *aperture_size *= 64; - else - *aperture_size *= 128; - break; - default: - /* 9xx supports large sizes, just look at the length */ - *aperture_size = pci_resource_len(dev->pdev, 2); - break; - } - - /* - * Some of the preallocated space is taken by the GTT - * and popup. GTT is 1K per MB of aperture size, and popup is 4K. - */ - if (IS_G4X(dev) || IS_PINEVIEW(dev) || IS_IRONLAKE(dev) || IS_GEN6(dev)) - overhead = 4096; - else - overhead = (*aperture_size / 1024) + 4096; - - if (IS_GEN6(dev)) { - /* SNB has memory control reg at 0x50.w */ - pci_read_config_word(dev->pdev, SNB_GMCH_CTRL, &tmp); - - switch (tmp & SNB_GMCH_GMS_STOLEN_MASK) { - case INTEL_855_GMCH_GMS_DISABLED: - DRM_ERROR("video memory is disabled\n"); - return -1; - case SNB_GMCH_GMS_STOLEN_32M: - stolen = 32 * 1024 * 1024; - break; - case SNB_GMCH_GMS_STOLEN_64M: - stolen = 64 * 1024 * 1024; - break; - case SNB_GMCH_GMS_STOLEN_96M: - stolen = 96 * 1024 * 1024; - break; - case SNB_GMCH_GMS_STOLEN_128M: - stolen = 128 * 1024 * 1024; - break; - case SNB_GMCH_GMS_STOLEN_160M: - stolen = 160 * 1024 * 1024; - break; - case SNB_GMCH_GMS_STOLEN_192M: - stolen = 192 * 1024 * 1024; - break; - case SNB_GMCH_GMS_STOLEN_224M: - stolen = 224 * 1024 * 1024; - break; - case SNB_GMCH_GMS_STOLEN_256M: - stolen = 256 * 1024 * 1024; - break; - case SNB_GMCH_GMS_STOLEN_288M: - stolen = 288 * 1024 * 1024; - break; - case SNB_GMCH_GMS_STOLEN_320M: - stolen = 320 * 1024 * 1024; - break; - case SNB_GMCH_GMS_STOLEN_352M: - stolen = 352 * 1024 * 1024; - break; - case SNB_GMCH_GMS_STOLEN_384M: - stolen = 384 * 1024 * 1024; - break; - case SNB_GMCH_GMS_STOLEN_416M: - stolen = 416 * 1024 * 1024; - break; - case SNB_GMCH_GMS_STOLEN_448M: - stolen = 448 * 1024 * 1024; - break; - case SNB_GMCH_GMS_STOLEN_480M: - stolen = 480 * 1024 * 1024; - break; - case SNB_GMCH_GMS_STOLEN_512M: - stolen = 512 * 1024 * 1024; - break; - default: - DRM_ERROR("unexpected GMCH_GMS value: 0x%02x\n", - tmp & SNB_GMCH_GMS_STOLEN_MASK); - return -1; - } - } else { - switch (tmp & INTEL_GMCH_GMS_MASK) { - case INTEL_855_GMCH_GMS_DISABLED: - DRM_ERROR("video memory is disabled\n"); - return -1; - case INTEL_855_GMCH_GMS_STOLEN_1M: - stolen = 1 * 1024 * 1024; - break; - case INTEL_855_GMCH_GMS_STOLEN_4M: - stolen = 4 * 1024 * 1024; - break; - case INTEL_855_GMCH_GMS_STOLEN_8M: - stolen = 8 * 1024 * 1024; - break; - case INTEL_855_GMCH_GMS_STOLEN_16M: - stolen = 16 * 1024 * 1024; - break; - case INTEL_855_GMCH_GMS_STOLEN_32M: - stolen = 32 * 1024 * 1024; - break; - case INTEL_915G_GMCH_GMS_STOLEN_48M: - stolen = 48 * 1024 * 1024; - break; - case INTEL_915G_GMCH_GMS_STOLEN_64M: - stolen = 64 * 1024 * 1024; - break; - case INTEL_GMCH_GMS_STOLEN_128M: - stolen = 128 * 1024 * 1024; - break; - case INTEL_GMCH_GMS_STOLEN_256M: - stolen = 256 * 1024 * 1024; - break; - case INTEL_GMCH_GMS_STOLEN_96M: - stolen = 96 * 1024 * 1024; - break; - case INTEL_GMCH_GMS_STOLEN_160M: - stolen = 160 * 1024 * 1024; - break; - case INTEL_GMCH_GMS_STOLEN_224M: - stolen = 224 * 1024 * 1024; - break; - case INTEL_GMCH_GMS_STOLEN_352M: - stolen = 352 * 1024 * 1024; - break; - default: - DRM_ERROR("unexpected GMCH_GMS value: 0x%02x\n", - tmp & INTEL_GMCH_GMS_MASK); - return -1; - } - } - - *preallocated_size = stolen - overhead; - - return 0; -} - #define PTE_ADDRESS_MASK 0xfffff000 #define PTE_ADDRESS_MASK_HIGH 0x000000f0 /* i915+ */ #define PTE_MAPPING_TYPE_UNCACHED (0 << 1) @@ -1249,7 +1083,7 @@ static void i915_setup_compression(struct drm_device *dev, int size) unsigned long ll_base = 0; /* Leave 1M for line length buffer & misc. */ - compressed_fb = drm_mm_search_free(&dev_priv->vram, size, 4096, 0); + compressed_fb = drm_mm_search_free(&dev_priv->mm.vram, size, 4096, 0); if (!compressed_fb) { dev_priv->no_fbc_reason = FBC_STOLEN_TOO_SMALL; i915_warn_stolen(dev); @@ -1270,7 +1104,7 @@ static void i915_setup_compression(struct drm_device *dev, int size) } if (!(IS_GM45(dev) || IS_IRONLAKE_M(dev))) { - compressed_llb = drm_mm_search_free(&dev_priv->vram, 4096, + compressed_llb = drm_mm_search_free(&dev_priv->mm.vram, 4096, 4096, 0); if (!compressed_llb) { i915_warn_stolen(dev); @@ -1366,8 +1200,8 @@ static int i915_load_modeset_init(struct drm_device *dev, struct drm_i915_private *dev_priv = dev->dev_private; int ret = 0; - /* Basic memrange allocator for stolen space (aka vram) */ - drm_mm_init(&dev_priv->vram, 0, prealloc_size); + /* Basic memrange allocator for stolen space (aka mm.vram) */ + drm_mm_init(&dev_priv->mm.vram, 0, prealloc_size); DRM_INFO("set up %ldM of stolen space\n", prealloc_size / (1024*1024)); /* We're off and running w/KMS */ @@ -2107,16 +1941,16 @@ int i915_driver_load(struct drm_device *dev, unsigned long flags) "performance may suffer.\n"); } - ret = i915_probe_agp(dev, &agp_size, &prealloc_size); - if (ret) + dev_priv->mm.gtt = intel_gtt_get(); + if (!dev_priv->mm.gtt) { + DRM_ERROR("Failed to initialize GTT\n"); + ret = -ENODEV; goto out_iomapfree; - - if (prealloc_size > intel_max_stolen) { - DRM_INFO("detected %dM stolen memory, trimming to %dM\n", - prealloc_size >> 20, intel_max_stolen >> 20); - prealloc_size = intel_max_stolen; } + prealloc_size = dev_priv->mm.gtt->gtt_stolen_entries << PAGE_SHIFT; + agp_size = dev_priv->mm.gtt->gtt_mappable_entries << PAGE_SHIFT; + dev_priv->wq = create_singlethread_workqueue("i915"); if (dev_priv->wq == NULL) { DRM_ERROR("Failed to create our workqueue.\n"); @@ -2301,7 +2135,7 @@ int i915_driver_unload(struct drm_device *dev) mutex_unlock(&dev->struct_mutex); if (I915_HAS_FBC(dev) && i915_powersave) i915_cleanup_compression(dev); - drm_mm_takedown(&dev_priv->vram); + drm_mm_takedown(&dev_priv->mm.vram); intel_cleanup_overlay(dev); } diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index d825ef2..c8b2200 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -305,8 +305,6 @@ typedef struct drm_i915_private { uint32_t last_instdone; uint32_t last_instdone1; - struct drm_mm vram; - unsigned long cfb_size; unsigned long cfb_pitch; int cfb_fence; @@ -511,6 +509,11 @@ typedef struct drm_i915_private { u32 saveMCHBAR_RENDER_STANDBY; struct { + /** Bridge to intel-gtt-ko */ + struct intel_gtt *gtt; + /** Memory allocator for GTT stolen memory */ + struct drm_mm vram; + /** Memory allocator for GTT */ struct drm_mm gtt_space; struct io_mapping *gtt_mapping; diff --git a/include/drm/intel-gtt.h b/include/drm/intel-gtt.h index 6769cb7..b3aa7ab 100644 --- a/include/drm/intel-gtt.h +++ b/include/drm/intel-gtt.h @@ -14,5 +14,7 @@ struct intel_gtt { unsigned int gtt_mappable_entries; }; +struct intel_gtt *intel_gtt_get(void); + #endif -- cgit v1.1 From f4433a8d5d3076775bdd1a996a47db7beb468ac0 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Wed, 8 Sep 2010 21:44:47 +0200 Subject: i915: snprintf returns large values snprintf() returns the number of bytes which would have been used if there was enough space. It can be larger than the size of the buffer. Obviously in this case the buffer is large enough but everyone just copy and pastes this code so it's better to limit it and set a good example. Signed-off-by: Dan Carpenter Signed-off-by: Chris Wilson --- drivers/gpu/drm/i915/i915_debugfs.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/gpu/drm/i915/i915_debugfs.c b/drivers/gpu/drm/i915/i915_debugfs.c index 2f3e017..7700ccf 100644 --- a/drivers/gpu/drm/i915/i915_debugfs.c +++ b/drivers/gpu/drm/i915/i915_debugfs.c @@ -886,6 +886,9 @@ i915_wedged_read(struct file *filp, "wedged : %d\n", atomic_read(&dev_priv->mm.wedged)); + if (len > sizeof (buf)) + len = sizeof (buf); + return simple_read_from_buffer(ubuf, max, ppos, buf, len); } -- cgit v1.1 From 7eaf5547d0460027b15a297bb15d80bdd600cb41 Mon Sep 17 00:00:00 2001 From: Jesse Barnes Date: Wed, 8 Sep 2010 12:41:59 -0700 Subject: drm/i915: fix eDP detection Panel needs to be powered up. Signed-off-by: Jesse Barnes Signed-off-by: Chris Wilson --- drivers/gpu/drm/i915/intel_dp.c | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c index eb6e676..38bf7cd 100644 --- a/drivers/gpu/drm/i915/intel_dp.c +++ b/drivers/gpu/drm/i915/intel_dp.c @@ -754,13 +754,14 @@ intel_dp_mode_set(struct drm_encoder *encoder, struct drm_display_mode *mode, } } -static void ironlake_edp_panel_on (struct drm_device *dev) +/* Returns true if the panel was already on when called */ +static bool ironlake_edp_panel_on (struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; u32 pp; if (I915_READ(PCH_PP_STATUS) & PP_ON) - return; + return true; pp = I915_READ(PCH_PP_CONTROL); @@ -780,6 +781,8 @@ static void ironlake_edp_panel_on (struct drm_device *dev) pp |= PANEL_POWER_RESET; /* restore panel reset bit */ I915_WRITE(PCH_PP_CONTROL, pp); POSTING_READ(PCH_PP_CONTROL); + + return false; } static void ironlake_edp_panel_off (struct drm_device *dev) @@ -860,7 +863,7 @@ static void intel_dp_prepare(struct drm_encoder *encoder) struct drm_i915_private *dev_priv = dev->dev_private; uint32_t dp_reg = I915_READ(intel_dp->output_reg); - if (IS_eDP(intel_dp)) { + if (IS_eDP(intel_dp) || IS_PCH_eDP(intel_dp)) { ironlake_edp_backlight_off(dev); ironlake_edp_panel_on(dev); ironlake_edp_pll_on(encoder); @@ -1365,7 +1368,11 @@ ironlake_dp_detect(struct drm_connector *connector) struct drm_encoder *encoder = intel_attached_encoder(connector); struct intel_dp *intel_dp = enc_to_intel_dp(encoder); enum drm_connector_status status; + bool was_on = false; + /* Panel needs power for AUX to work */ + if (IS_eDP(intel_dp) || IS_PCH_eDP(intel_dp)) + was_on = ironlake_edp_panel_on(connector->dev); status = connector_status_disconnected; if (intel_dp_aux_native_read(intel_dp, 0x000, intel_dp->dpcd, @@ -1376,6 +1383,8 @@ ironlake_dp_detect(struct drm_connector *connector) } DRM_DEBUG_KMS("DPCD: %hx%hx%hx%hx\n", intel_dp->dpcd[0], intel_dp->dpcd[1], intel_dp->dpcd[2], intel_dp->dpcd[3]); + if ((IS_eDP(intel_dp) || IS_PCH_eDP(intel_dp)) && !was_on) + ironlake_edp_panel_off(connector->dev); return status; } -- cgit v1.1 From 6176b8f908a58a7affaacf6f3a90ef14325686f0 Mon Sep 17 00:00:00 2001 From: Jesse Barnes Date: Wed, 8 Sep 2010 12:42:00 -0700 Subject: drm/i915: use 125MHz reference clock for PCH attached eDP Fix the test so we don't try to use the 450MHz refclk on PCH attached eDP. References: https://bugs.freedesktop.org/show_bug.cgi?id=29141 Signed-off-by: Jesse Barnes Signed-off-by: Chris Wilson --- drivers/gpu/drm/i915/intel_dp.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c index 38bf7cd..8c1da1e 100644 --- a/drivers/gpu/drm/i915/intel_dp.c +++ b/drivers/gpu/drm/i915/intel_dp.c @@ -246,8 +246,11 @@ intel_dp_aux_ch(struct intel_dp *intel_dp, /* The clock divider is based off the hrawclk, * and would like to run at 2MHz. So, take the * hrawclk value and divide by 2 and use that + * + * Note that PCH attached eDP panels should use a 125MHz input + * clock divider. */ - if (IS_eDP(intel_dp)) { + if (IS_eDP(intel_dp) && !IS_PCH_eDP(intel_dp)) { if (IS_GEN6(dev)) aux_clock_divider = 200; /* SNB eDP input clock at 400Mhz */ else -- cgit v1.1 From b2094bbad48a59f59b115832879121aa210841f0 Mon Sep 17 00:00:00 2001 From: Jesse Barnes Date: Wed, 8 Sep 2010 12:42:01 -0700 Subject: drm/i915: use VDD AUX for panel power around detection and in prepare Mode setting sequence specifies that we use VDD AUX for configuration and detection, and early in the mode set sequence. Only later (after DP_A has started training) should we actually enable panel power. Signed-off-by: Jesse Barnes [ickle: checkpatch.pl complaining about whitespace] Signed-off-by: Chris Wilson --- drivers/gpu/drm/i915/intel_dp.c | 35 +++++++++++++++++++++++++++++------ 1 file changed, 29 insertions(+), 6 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c index 8c1da1e..3a4e2a6 100644 --- a/drivers/gpu/drm/i915/intel_dp.c +++ b/drivers/gpu/drm/i915/intel_dp.c @@ -813,6 +813,28 @@ static void ironlake_edp_panel_off (struct drm_device *dev) POSTING_READ(PCH_PP_CONTROL); } +static void ironlake_edp_panel_vdd_on(struct drm_device *dev) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + u32 pp; + + pp = I915_READ(PCH_PP_CONTROL); + pp |= EDP_FORCE_VDD; + I915_WRITE(PCH_PP_CONTROL, pp); + POSTING_READ(PCH_PP_CONTROL); +} + +static void ironlake_edp_panel_vdd_off(struct drm_device *dev) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + u32 pp; + + pp = I915_READ(PCH_PP_CONTROL); + pp &= ~EDP_FORCE_VDD; + I915_WRITE(PCH_PP_CONTROL, pp); + POSTING_READ(PCH_PP_CONTROL); +} + static void ironlake_edp_backlight_on (struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; @@ -868,7 +890,7 @@ static void intel_dp_prepare(struct drm_encoder *encoder) if (IS_eDP(intel_dp) || IS_PCH_eDP(intel_dp)) { ironlake_edp_backlight_off(dev); - ironlake_edp_panel_on(dev); + ironlake_edp_panel_vdd_on(dev); ironlake_edp_pll_on(encoder); } if (dp_reg & DP_PORT_EN) @@ -885,8 +907,10 @@ static void intel_dp_commit(struct drm_encoder *encoder) if (!(dp_reg & DP_PORT_EN)) { intel_dp_link_train(intel_dp); } - if (IS_eDP(intel_dp) || IS_PCH_eDP(intel_dp)) + if (IS_eDP(intel_dp) || IS_PCH_eDP(intel_dp)) { + ironlake_edp_panel_on(dev); ironlake_edp_backlight_on(dev); + } } static void @@ -1371,11 +1395,10 @@ ironlake_dp_detect(struct drm_connector *connector) struct drm_encoder *encoder = intel_attached_encoder(connector); struct intel_dp *intel_dp = enc_to_intel_dp(encoder); enum drm_connector_status status; - bool was_on = false; /* Panel needs power for AUX to work */ if (IS_eDP(intel_dp) || IS_PCH_eDP(intel_dp)) - was_on = ironlake_edp_panel_on(connector->dev); + ironlake_edp_panel_vdd_on(connector->dev); status = connector_status_disconnected; if (intel_dp_aux_native_read(intel_dp, 0x000, intel_dp->dpcd, @@ -1386,8 +1409,8 @@ ironlake_dp_detect(struct drm_connector *connector) } DRM_DEBUG_KMS("DPCD: %hx%hx%hx%hx\n", intel_dp->dpcd[0], intel_dp->dpcd[1], intel_dp->dpcd[2], intel_dp->dpcd[3]); - if ((IS_eDP(intel_dp) || IS_PCH_eDP(intel_dp)) && !was_on) - ironlake_edp_panel_off(connector->dev); + if (IS_eDP(intel_dp) || IS_PCH_eDP(intel_dp)) + ironlake_edp_panel_vdd_off(connector->dev); return status; } -- cgit v1.1 From 33a34e4e5969c5272cd6cb88f2e01c97218dd80b Mon Sep 17 00:00:00 2001 From: Jesse Barnes Date: Wed, 8 Sep 2010 12:42:02 -0700 Subject: drm/i915: split DP link training across panel power sequencing Mode set sequence requires that we start training, then enable the panel, then complete training. So split the DP training function into two parts; the first enables the DP port and sets training pattern 1 and the second completes the training. As part of this, remove some redundant function args from the various DP handling functions and use the intel_dp fields everywhere we can. Signed-off-by: Jesse Barnes [ickle: removed first ironlake_edp_backlight_on() on advice of jbarnes] Signed-off-by: Chris Wilson --- drivers/gpu/drm/i915/intel_dp.c | 121 +++++++++++++++++++++------------------- 1 file changed, 65 insertions(+), 56 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c index 3a4e2a6..effbbe0 100644 --- a/drivers/gpu/drm/i915/intel_dp.c +++ b/drivers/gpu/drm/i915/intel_dp.c @@ -58,6 +58,8 @@ struct intel_dp { struct i2c_adapter adapter; struct i2c_algo_dp_aux_data algo; bool is_pch_edp; + uint8_t train_set[4]; + uint8_t link_status[DP_LINK_STATUS_SIZE]; }; static struct intel_dp *enc_to_intel_dp(struct drm_encoder *encoder) @@ -65,7 +67,8 @@ static struct intel_dp *enc_to_intel_dp(struct drm_encoder *encoder) return container_of(enc_to_intel_encoder(encoder), struct intel_dp, base); } -static void intel_dp_link_train(struct intel_dp *intel_dp); +static void intel_dp_start_link_train(struct intel_dp *intel_dp); +static void intel_dp_complete_link_train(struct intel_dp *intel_dp); static void intel_dp_link_down(struct intel_dp *intel_dp); void @@ -901,16 +904,16 @@ static void intel_dp_commit(struct drm_encoder *encoder) { struct intel_dp *intel_dp = enc_to_intel_dp(encoder); struct drm_device *dev = encoder->dev; - struct drm_i915_private *dev_priv = dev->dev_private; - uint32_t dp_reg = I915_READ(intel_dp->output_reg); - if (!(dp_reg & DP_PORT_EN)) { - intel_dp_link_train(intel_dp); - } - if (IS_eDP(intel_dp) || IS_PCH_eDP(intel_dp)) { + intel_dp_start_link_train(intel_dp); + + if (IS_eDP(intel_dp) || IS_PCH_eDP(intel_dp)) ironlake_edp_panel_on(dev); + + intel_dp_complete_link_train(intel_dp); + + if (IS_eDP(intel_dp) || IS_PCH_eDP(intel_dp)) ironlake_edp_backlight_on(dev); - } } static void @@ -932,9 +935,10 @@ intel_dp_dpms(struct drm_encoder *encoder, int mode) ironlake_edp_pll_off(encoder); } else { if (!(dp_reg & DP_PORT_EN)) { + intel_dp_start_link_train(intel_dp); if (IS_eDP(intel_dp) || IS_PCH_eDP(intel_dp)) ironlake_edp_panel_on(dev); - intel_dp_link_train(intel_dp); + intel_dp_complete_link_train(intel_dp); if (IS_eDP(intel_dp) || IS_PCH_eDP(intel_dp)) ironlake_edp_backlight_on(dev); } @@ -947,14 +951,13 @@ intel_dp_dpms(struct drm_encoder *encoder, int mode) * link status information */ static bool -intel_dp_get_link_status(struct intel_dp *intel_dp, - uint8_t link_status[DP_LINK_STATUS_SIZE]) +intel_dp_get_link_status(struct intel_dp *intel_dp) { int ret; ret = intel_dp_aux_native_read(intel_dp, DP_LANE0_1_STATUS, - link_status, DP_LINK_STATUS_SIZE); + intel_dp->link_status, DP_LINK_STATUS_SIZE); if (ret != DP_LINK_STATUS_SIZE) return false; return true; @@ -1029,18 +1032,15 @@ intel_dp_pre_emphasis_max(uint8_t voltage_swing) } static void -intel_get_adjust_train(struct intel_dp *intel_dp, - uint8_t link_status[DP_LINK_STATUS_SIZE], - int lane_count, - uint8_t train_set[4]) +intel_get_adjust_train(struct intel_dp *intel_dp) { uint8_t v = 0; uint8_t p = 0; int lane; - for (lane = 0; lane < lane_count; lane++) { - uint8_t this_v = intel_get_adjust_request_voltage(link_status, lane); - uint8_t this_p = intel_get_adjust_request_pre_emphasis(link_status, lane); + for (lane = 0; lane < intel_dp->lane_count; lane++) { + uint8_t this_v = intel_get_adjust_request_voltage(intel_dp->link_status, lane); + uint8_t this_p = intel_get_adjust_request_pre_emphasis(intel_dp->link_status, lane); if (this_v > v) v = this_v; @@ -1055,7 +1055,7 @@ intel_get_adjust_train(struct intel_dp *intel_dp, p = intel_dp_pre_emphasis_max(v) | DP_TRAIN_MAX_PRE_EMPHASIS_REACHED; for (lane = 0; lane < 4; lane++) - train_set[lane] = v | p; + intel_dp->train_set[lane] = v | p; } static uint32_t @@ -1146,18 +1146,18 @@ intel_clock_recovery_ok(uint8_t link_status[DP_LINK_STATUS_SIZE], int lane_count DP_LANE_CHANNEL_EQ_DONE|\ DP_LANE_SYMBOL_LOCKED) static bool -intel_channel_eq_ok(uint8_t link_status[DP_LINK_STATUS_SIZE], int lane_count) +intel_channel_eq_ok(struct intel_dp *intel_dp) { uint8_t lane_align; uint8_t lane_status; int lane; - lane_align = intel_dp_link_status(link_status, + lane_align = intel_dp_link_status(intel_dp->link_status, DP_LANE_ALIGN_STATUS_UPDATED); if ((lane_align & DP_INTERLANE_ALIGN_DONE) == 0) return false; - for (lane = 0; lane < lane_count; lane++) { - lane_status = intel_get_lane_status(link_status, lane); + for (lane = 0; lane < intel_dp->lane_count; lane++) { + lane_status = intel_get_lane_status(intel_dp->link_status, lane); if ((lane_status & CHANNEL_EQ_BITS) != CHANNEL_EQ_BITS) return false; } @@ -1168,7 +1168,6 @@ static bool intel_dp_set_link_train(struct intel_dp *intel_dp, uint32_t dp_reg_value, uint8_t dp_train_pat, - uint8_t train_set[4], bool first) { struct drm_device *dev = intel_dp->base.enc.dev; @@ -1186,24 +1185,21 @@ intel_dp_set_link_train(struct intel_dp *intel_dp, dp_train_pat); ret = intel_dp_aux_native_write(intel_dp, - DP_TRAINING_LANE0_SET, train_set, 4); + DP_TRAINING_LANE0_SET, intel_dp->train_set, 4); if (ret != 4) return false; return true; } +/* Enable corresponding port and start training pattern 1 */ static void -intel_dp_link_train(struct intel_dp *intel_dp) +intel_dp_start_link_train(struct intel_dp *intel_dp) { struct drm_device *dev = intel_dp->base.enc.dev; - struct drm_i915_private *dev_priv = dev->dev_private; - uint8_t train_set[4]; - uint8_t link_status[DP_LINK_STATUS_SIZE]; int i; uint8_t voltage; bool clock_recovery = false; - bool channel_eq = false; bool first = true; int tries; u32 reg; @@ -1219,18 +1215,18 @@ intel_dp_link_train(struct intel_dp *intel_dp) DP &= ~DP_LINK_TRAIN_MASK_CPT; else DP &= ~DP_LINK_TRAIN_MASK; - memset(train_set, 0, 4); + memset(intel_dp->train_set, 0, 4); voltage = 0xff; tries = 0; clock_recovery = false; for (;;) { - /* Use train_set[0] to set the voltage and pre emphasis values */ + /* Use intel_dp->train_set[0] to set the voltage and pre emphasis values */ uint32_t signal_levels; if (IS_GEN6(dev) && IS_eDP(intel_dp)) { - signal_levels = intel_gen6_edp_signal_levels(train_set[0]); + signal_levels = intel_gen6_edp_signal_levels(intel_dp->train_set[0]); DP = (DP & ~EDP_LINK_TRAIN_VOL_EMP_MASK_SNB) | signal_levels; } else { - signal_levels = intel_dp_signal_levels(train_set[0], intel_dp->lane_count); + signal_levels = intel_dp_signal_levels(intel_dp->train_set[0], intel_dp->lane_count); DP = (DP & ~(DP_VOLTAGE_MASK|DP_PRE_EMPHASIS_MASK)) | signal_levels; } @@ -1240,52 +1236,65 @@ intel_dp_link_train(struct intel_dp *intel_dp) reg = DP | DP_LINK_TRAIN_PAT_1; if (!intel_dp_set_link_train(intel_dp, reg, - DP_TRAINING_PATTERN_1, train_set, first)) + DP_TRAINING_PATTERN_1, first)) break; first = false; /* Set training pattern 1 */ udelay(100); - if (!intel_dp_get_link_status(intel_dp, link_status)) + if (!intel_dp_get_link_status(intel_dp)) break; - if (intel_clock_recovery_ok(link_status, intel_dp->lane_count)) { + if (intel_clock_recovery_ok(intel_dp->link_status, intel_dp->lane_count)) { clock_recovery = true; break; } /* Check to see if we've tried the max voltage */ for (i = 0; i < intel_dp->lane_count; i++) - if ((train_set[i] & DP_TRAIN_MAX_SWING_REACHED) == 0) + if ((intel_dp->train_set[i] & DP_TRAIN_MAX_SWING_REACHED) == 0) break; if (i == intel_dp->lane_count) break; /* Check to see if we've tried the same voltage 5 times */ - if ((train_set[0] & DP_TRAIN_VOLTAGE_SWING_MASK) == voltage) { + if ((intel_dp->train_set[0] & DP_TRAIN_VOLTAGE_SWING_MASK) == voltage) { ++tries; if (tries == 5) break; } else tries = 0; - voltage = train_set[0] & DP_TRAIN_VOLTAGE_SWING_MASK; + voltage = intel_dp->train_set[0] & DP_TRAIN_VOLTAGE_SWING_MASK; - /* Compute new train_set as requested by target */ - intel_get_adjust_train(intel_dp, link_status, intel_dp->lane_count, train_set); + /* Compute new intel_dp->train_set as requested by target */ + intel_get_adjust_train(intel_dp); } + intel_dp->DP = DP; +} + +static void +intel_dp_complete_link_train(struct intel_dp *intel_dp) +{ + struct drm_device *dev = intel_dp->base.enc.dev; + struct drm_i915_private *dev_priv = dev->dev_private; + bool channel_eq = false; + int tries; + u32 reg; + uint32_t DP = intel_dp->DP; + /* channel equalization */ tries = 0; channel_eq = false; for (;;) { - /* Use train_set[0] to set the voltage and pre emphasis values */ + /* Use intel_dp->train_set[0] to set the voltage and pre emphasis values */ uint32_t signal_levels; if (IS_GEN6(dev) && IS_eDP(intel_dp)) { - signal_levels = intel_gen6_edp_signal_levels(train_set[0]); + signal_levels = intel_gen6_edp_signal_levels(intel_dp->train_set[0]); DP = (DP & ~EDP_LINK_TRAIN_VOL_EMP_MASK_SNB) | signal_levels; } else { - signal_levels = intel_dp_signal_levels(train_set[0], intel_dp->lane_count); + signal_levels = intel_dp_signal_levels(intel_dp->train_set[0], intel_dp->lane_count); DP = (DP & ~(DP_VOLTAGE_MASK|DP_PRE_EMPHASIS_MASK)) | signal_levels; } @@ -1296,15 +1305,15 @@ intel_dp_link_train(struct intel_dp *intel_dp) /* channel eq pattern */ if (!intel_dp_set_link_train(intel_dp, reg, - DP_TRAINING_PATTERN_2, train_set, + DP_TRAINING_PATTERN_2, false)) break; udelay(400); - if (!intel_dp_get_link_status(intel_dp, link_status)) + if (!intel_dp_get_link_status(intel_dp)) break; - if (intel_channel_eq_ok(link_status, intel_dp->lane_count)) { + if (intel_channel_eq_ok(intel_dp)) { channel_eq = true; break; } @@ -1313,8 +1322,8 @@ intel_dp_link_train(struct intel_dp *intel_dp) if (tries > 5) break; - /* Compute new train_set as requested by target */ - intel_get_adjust_train(intel_dp, link_status, intel_dp->lane_count, train_set); + /* Compute new intel_dp->train_set as requested by target */ + intel_get_adjust_train(intel_dp); ++tries; } @@ -1375,18 +1384,18 @@ intel_dp_link_down(struct intel_dp *intel_dp) static void intel_dp_check_link_status(struct intel_dp *intel_dp) { - uint8_t link_status[DP_LINK_STATUS_SIZE]; - if (!intel_dp->base.enc.crtc) return; - if (!intel_dp_get_link_status(intel_dp, link_status)) { + if (!intel_dp_get_link_status(intel_dp)) { intel_dp_link_down(intel_dp); return; } - if (!intel_channel_eq_ok(link_status, intel_dp->lane_count)) - intel_dp_link_train(intel_dp); + if (!intel_channel_eq_ok(intel_dp)) { + intel_dp_start_link_train(intel_dp); + intel_dp_complete_link_train(intel_dp); + } } static enum drm_connector_status -- cgit v1.1 From 3969c9c927b0bdb1e477a1eda60743143a75e4a5 Mon Sep 17 00:00:00 2001 From: Jesse Barnes Date: Wed, 8 Sep 2010 12:42:03 -0700 Subject: drm/i915: don't change VDD AUX status in panel power functions Mode set sequence outlines when the AUX VDD bit should be set and cleared, and it's separate from the panel power sequence. Signed-off-by: Jesse Barnes Signed-off-by: Chris Wilson --- 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 effbbe0..153a593 100644 --- a/drivers/gpu/drm/i915/intel_dp.c +++ b/drivers/gpu/drm/i915/intel_dp.c @@ -783,7 +783,7 @@ static bool ironlake_edp_panel_on (struct drm_device *dev) DRM_ERROR("panel on wait timed out: 0x%08x\n", I915_READ(PCH_PP_STATUS)); - pp &= ~(PANEL_UNLOCK_REGS | EDP_FORCE_VDD); + pp &= ~(PANEL_UNLOCK_REGS); pp |= PANEL_POWER_RESET; /* restore panel reset bit */ I915_WRITE(PCH_PP_CONTROL, pp); POSTING_READ(PCH_PP_CONTROL); @@ -811,7 +811,7 @@ static void ironlake_edp_panel_off (struct drm_device *dev) I915_READ(PCH_PP_STATUS)); /* Make sure VDD is enabled so DP AUX will work */ - pp |= EDP_FORCE_VDD | PANEL_POWER_RESET; /* restore panel reset bit */ + pp |= PANEL_POWER_RESET; /* restore panel reset bit */ I915_WRITE(PCH_PP_CONTROL, pp); POSTING_READ(PCH_PP_CONTROL); } -- cgit v1.1 From 3ba5c569c4a99c43bdac9f0c1c65e15a7b3390b9 Mon Sep 17 00:00:00 2001 From: Jesse Barnes Date: Wed, 25 Aug 2010 13:09:48 -0700 Subject: drm/i915: make sure VDD AUX power has time to settle When turning on or off the VDD AUX bit, we need to give the panel time to start or stop or AUX transactions may fail. Signed-off-by: Jesse Barnes Signed-off-by: Chris Wilson --- drivers/gpu/drm/i915/intel_dp.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c index 153a593..bcd81f9 100644 --- a/drivers/gpu/drm/i915/intel_dp.c +++ b/drivers/gpu/drm/i915/intel_dp.c @@ -825,6 +825,7 @@ static void ironlake_edp_panel_vdd_on(struct drm_device *dev) pp |= EDP_FORCE_VDD; I915_WRITE(PCH_PP_CONTROL, pp); POSTING_READ(PCH_PP_CONTROL); + msleep(300); } static void ironlake_edp_panel_vdd_off(struct drm_device *dev) @@ -836,6 +837,7 @@ static void ironlake_edp_panel_vdd_off(struct drm_device *dev) pp &= ~EDP_FORCE_VDD; I915_WRITE(PCH_PP_CONTROL, pp); POSTING_READ(PCH_PP_CONTROL); + msleep(300); } static void ironlake_edp_backlight_on (struct drm_device *dev) -- cgit v1.1 From 2c9d97545914cc764786702f361a1f1c9bb8dfa9 Mon Sep 17 00:00:00 2001 From: Jesse Barnes Date: Wed, 8 Sep 2010 12:42:05 -0700 Subject: drm/i915: make sure panel is sequenced off when starting a mode set Otherwise we may not be able to train the DP link. Signed-off-by: Jesse Barnes Signed-off-by: Chris Wilson --- drivers/gpu/drm/i915/intel_dp.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c index bcd81f9..27805a9 100644 --- a/drivers/gpu/drm/i915/intel_dp.c +++ b/drivers/gpu/drm/i915/intel_dp.c @@ -894,6 +894,7 @@ static void intel_dp_prepare(struct drm_encoder *encoder) uint32_t dp_reg = I915_READ(intel_dp->output_reg); if (IS_eDP(intel_dp) || IS_PCH_eDP(intel_dp)) { + ironlake_edp_panel_off(dev); ironlake_edp_backlight_off(dev); ironlake_edp_panel_vdd_on(dev); ironlake_edp_pll_on(encoder); -- cgit v1.1 From 1af5fa1b7e5ff8332f8a2ee3c5fb44d93b34868d Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Wed, 8 Sep 2010 21:07:28 +0100 Subject: drm/i915/dp: Flush the PLL register write before sleeping Signed-off-by: Chris Wilson --- drivers/gpu/drm/i915/intel_dp.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c index 27805a9..c7aa29b 100644 --- a/drivers/gpu/drm/i915/intel_dp.c +++ b/drivers/gpu/drm/i915/intel_dp.c @@ -883,6 +883,7 @@ static void ironlake_edp_pll_off(struct drm_encoder *encoder) dpa_ctl = I915_READ(DP_A); dpa_ctl |= DP_PLL_ENABLE; I915_WRITE(DP_A, dpa_ctl); + POSTING_READ(DP_A); udelay(200); } -- cgit v1.1 From 4ef69c7a64b78d477d1666eba258ca049e8bac91 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Thu, 9 Sep 2010 15:14:28 +0100 Subject: drm/i915: Rename intel_encoder->enc to base for consistency [Patch is slightly larger than is strictly necessary to fixup surrounding checkpatch.pl errors.] Signed-off-by: Chris Wilson Reviewed-by: Jesse Barnes --- drivers/gpu/drm/i915/i915_irq.c | 16 ++--- drivers/gpu/drm/i915/intel_crt.c | 14 ++-- drivers/gpu/drm/i915/intel_display.c | 52 +++++++-------- drivers/gpu/drm/i915/intel_dp.c | 28 ++++---- drivers/gpu/drm/i915/intel_drv.h | 4 +- drivers/gpu/drm/i915/intel_dvo.c | 8 +-- drivers/gpu/drm/i915/intel_hdmi.c | 8 +-- drivers/gpu/drm/i915/intel_lvds.c | 10 +-- drivers/gpu/drm/i915/intel_modes.c | 4 +- drivers/gpu/drm/i915/intel_sdvo.c | 124 +++++++++++++++++------------------ drivers/gpu/drm/i915/intel_tv.c | 15 +++-- 11 files changed, 137 insertions(+), 146 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c index 2f7f7cb..33525c9 100644 --- a/drivers/gpu/drm/i915/i915_irq.c +++ b/drivers/gpu/drm/i915/i915_irq.c @@ -260,16 +260,12 @@ static void i915_hotplug_work_func(struct work_struct *work) hotplug_work); struct drm_device *dev = dev_priv->dev; struct drm_mode_config *mode_config = &dev->mode_config; - struct drm_encoder *encoder; - - if (mode_config->num_encoder) { - list_for_each_entry(encoder, &mode_config->encoder_list, head) { - struct intel_encoder *intel_encoder = enc_to_intel_encoder(encoder); - - if (intel_encoder->hot_plug) - (*intel_encoder->hot_plug) (intel_encoder); - } - } + struct intel_encoder *encoder; + + list_for_each_entry(encoder, &mode_config->encoder_list, base.head) + if (encoder->hot_plug) + encoder->hot_plug(encoder); + /* Just fire off a uevent and let userspace tell us what to do */ drm_helper_hpd_irq_event(dev); } diff --git a/drivers/gpu/drm/i915/intel_crt.c b/drivers/gpu/drm/i915/intel_crt.c index 6262797..e3f5e21 100644 --- a/drivers/gpu/drm/i915/intel_crt.c +++ b/drivers/gpu/drm/i915/intel_crt.c @@ -263,7 +263,7 @@ static bool intel_crt_detect_hotplug(struct drm_connector *connector) static bool intel_crt_detect_ddc(struct drm_encoder *encoder) { - struct intel_encoder *intel_encoder = enc_to_intel_encoder(encoder); + struct intel_encoder *intel_encoder = to_intel_encoder(encoder); /* CRT should always be at 0, but check anyway */ if (intel_encoder->type != INTEL_OUTPUT_ANALOG) @@ -275,7 +275,7 @@ static bool intel_crt_detect_ddc(struct drm_encoder *encoder) static enum drm_connector_status intel_crt_load_detect(struct drm_crtc *crtc, struct intel_encoder *intel_encoder) { - struct drm_encoder *encoder = &intel_encoder->enc; + struct drm_encoder *encoder = &intel_encoder->base; struct drm_device *dev = encoder->dev; struct drm_i915_private *dev_priv = dev->dev_private; struct intel_crtc *intel_crtc = to_intel_crtc(crtc); @@ -405,7 +405,7 @@ static enum drm_connector_status intel_crt_detect(struct drm_connector *connecto { struct drm_device *dev = connector->dev; struct drm_encoder *encoder = intel_attached_encoder(connector); - struct intel_encoder *intel_encoder = enc_to_intel_encoder(encoder); + struct intel_encoder *intel_encoder = to_intel_encoder(encoder); struct drm_crtc *crtc; int dpms_mode; enum drm_connector_status status; @@ -448,7 +448,7 @@ static int intel_crt_get_modes(struct drm_connector *connector) { int ret; struct drm_encoder *encoder = intel_attached_encoder(connector); - struct intel_encoder *intel_encoder = enc_to_intel_encoder(encoder); + struct intel_encoder *intel_encoder = to_intel_encoder(encoder); struct i2c_adapter *ddc_bus; struct drm_device *dev = connector->dev; @@ -533,11 +533,11 @@ void intel_crt_init(struct drm_device *dev) drm_connector_init(dev, &intel_connector->base, &intel_crt_connector_funcs, DRM_MODE_CONNECTOR_VGA); - drm_encoder_init(dev, &intel_encoder->enc, &intel_crt_enc_funcs, + drm_encoder_init(dev, &intel_encoder->base, &intel_crt_enc_funcs, DRM_MODE_ENCODER_DAC); drm_mode_connector_attach_encoder(&intel_connector->base, - &intel_encoder->enc); + &intel_encoder->base); /* Set up the DDC bus. */ if (HAS_PCH_SPLIT(dev)) @@ -563,7 +563,7 @@ void intel_crt_init(struct drm_device *dev) connector->interlace_allowed = 1; connector->doublescan_allowed = 0; - drm_encoder_helper_add(&intel_encoder->enc, &intel_crt_helper_funcs); + drm_encoder_helper_add(&intel_encoder->base, &intel_crt_helper_funcs); drm_connector_helper_add(connector, &intel_crt_connector_helper_funcs); drm_sysfs_connector_add(connector); diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 4b23646..24c7b0e 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -744,20 +744,17 @@ static void intel_clock(struct drm_device *dev, int refclk, intel_clock_t *clock /** * Returns whether any output on the specified pipe is of the specified type */ -bool intel_pipe_has_type (struct drm_crtc *crtc, int type) +bool intel_pipe_has_type(struct drm_crtc *crtc, int type) { - struct drm_device *dev = crtc->dev; - struct drm_mode_config *mode_config = &dev->mode_config; - struct drm_encoder *l_entry; - - list_for_each_entry(l_entry, &mode_config->encoder_list, head) { - if (l_entry && l_entry->crtc == crtc) { - struct intel_encoder *intel_encoder = enc_to_intel_encoder(l_entry); - if (intel_encoder->type == type) - return true; - } - } - return false; + struct drm_device *dev = crtc->dev; + struct drm_mode_config *mode_config = &dev->mode_config; + struct intel_encoder *encoder; + + list_for_each_entry(encoder, &mode_config->encoder_list, base.head) + if (encoder->base.crtc == crtc && encoder->type == type) + return true; + + return false; } #define INTELPllInvalid(s) do { /* DRM_DEBUG(s); */ return false; } while (0) @@ -2459,7 +2456,7 @@ void intel_encoder_commit (struct drm_encoder *encoder) void intel_encoder_destroy(struct drm_encoder *encoder) { - struct intel_encoder *intel_encoder = enc_to_intel_encoder(encoder); + struct intel_encoder *intel_encoder = to_intel_encoder(encoder); if (intel_encoder->ddc_bus) intel_i2c_destroy(intel_encoder->ddc_bus); @@ -3540,7 +3537,7 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc, if (encoder->crtc != crtc) continue; - intel_encoder = enc_to_intel_encoder(encoder); + intel_encoder = to_intel_encoder(encoder); switch (intel_encoder->type) { case INTEL_OUTPUT_LVDS: is_lvds = true; @@ -4430,7 +4427,7 @@ struct drm_crtc *intel_get_load_detect_pipe(struct intel_encoder *intel_encoder, struct intel_crtc *intel_crtc; struct drm_crtc *possible_crtc; struct drm_crtc *supported_crtc =NULL; - struct drm_encoder *encoder = &intel_encoder->enc; + struct drm_encoder *encoder = &intel_encoder->base; struct drm_crtc *crtc = NULL; struct drm_device *dev = encoder->dev; struct drm_encoder_helper_funcs *encoder_funcs = encoder->helper_private; @@ -4511,7 +4508,7 @@ struct drm_crtc *intel_get_load_detect_pipe(struct intel_encoder *intel_encoder, void intel_release_load_detect_pipe(struct intel_encoder *intel_encoder, struct drm_connector *connector, int dpms_mode) { - struct drm_encoder *encoder = &intel_encoder->enc; + struct drm_encoder *encoder = &intel_encoder->base; struct drm_device *dev = encoder->dev; struct drm_crtc *crtc = encoder->crtc; struct drm_encoder_helper_funcs *encoder_funcs = encoder->helper_private; @@ -5243,24 +5240,23 @@ struct drm_crtc *intel_get_crtc_from_pipe(struct drm_device *dev, int pipe) static int intel_encoder_clones(struct drm_device *dev, int type_mask) { + struct intel_encoder *encoder; int index_mask = 0; - struct drm_encoder *encoder; int entry = 0; - list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) { - struct intel_encoder *intel_encoder = enc_to_intel_encoder(encoder); - if (type_mask & intel_encoder->clone_mask) + list_for_each_entry(encoder, &dev->mode_config.encoder_list, base.head) { + if (type_mask & encoder->clone_mask) index_mask |= (1 << entry); entry++; } + return index_mask; } - static void intel_setup_outputs(struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; - struct drm_encoder *encoder; + struct intel_encoder *encoder; bool dpd_is_edp = false; if (IS_MOBILE(dev) && !IS_I830(dev)) @@ -5349,12 +5345,10 @@ static void intel_setup_outputs(struct drm_device *dev) if (SUPPORTS_TV(dev)) intel_tv_init(dev); - list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) { - struct intel_encoder *intel_encoder = enc_to_intel_encoder(encoder); - - encoder->possible_crtcs = intel_encoder->crtc_mask; - encoder->possible_clones = intel_encoder_clones(dev, - intel_encoder->clone_mask); + list_for_each_entry(encoder, &dev->mode_config.encoder_list, base.head) { + encoder->base.possible_crtcs = encoder->crtc_mask; + encoder->base.possible_clones = + intel_encoder_clones(dev, encoder->clone_mask); } } diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c index c7aa29b..6cdc53d 100644 --- a/drivers/gpu/drm/i915/intel_dp.c +++ b/drivers/gpu/drm/i915/intel_dp.c @@ -64,7 +64,7 @@ struct intel_dp { static struct intel_dp *enc_to_intel_dp(struct drm_encoder *encoder) { - return container_of(enc_to_intel_encoder(encoder), struct intel_dp, base); + return container_of(encoder, struct intel_dp, base.base); } static void intel_dp_start_link_train(struct intel_dp *intel_dp); @@ -236,7 +236,7 @@ intel_dp_aux_ch(struct intel_dp *intel_dp, uint8_t *recv, int recv_size) { uint32_t output_reg = intel_dp->output_reg; - struct drm_device *dev = intel_dp->base.enc.dev; + struct drm_device *dev = intel_dp->base.base.dev; struct drm_i915_private *dev_priv = dev->dev_private; uint32_t ch_ctl = output_reg + 0x10; uint32_t ch_data = ch_ctl + 4; @@ -704,7 +704,7 @@ intel_dp_mode_set(struct drm_encoder *encoder, struct drm_display_mode *mode, { struct drm_device *dev = encoder->dev; struct intel_dp *intel_dp = enc_to_intel_dp(encoder); - struct drm_crtc *crtc = intel_dp->base.enc.crtc; + struct drm_crtc *crtc = intel_dp->base.base.crtc; struct intel_crtc *intel_crtc = to_intel_crtc(crtc); intel_dp->DP = (DP_VOLTAGE_0_4 | @@ -1174,9 +1174,9 @@ intel_dp_set_link_train(struct intel_dp *intel_dp, uint8_t dp_train_pat, bool first) { - struct drm_device *dev = intel_dp->base.enc.dev; + struct drm_device *dev = intel_dp->base.base.dev; struct drm_i915_private *dev_priv = dev->dev_private; - struct intel_crtc *intel_crtc = to_intel_crtc(intel_dp->base.enc.crtc); + struct intel_crtc *intel_crtc = to_intel_crtc(intel_dp->base.base.crtc); int ret; I915_WRITE(intel_dp->output_reg, dp_reg_value); @@ -1200,7 +1200,7 @@ intel_dp_set_link_train(struct intel_dp *intel_dp, static void intel_dp_start_link_train(struct intel_dp *intel_dp) { - struct drm_device *dev = intel_dp->base.enc.dev; + struct drm_device *dev = intel_dp->base.base.dev; int i; uint8_t voltage; bool clock_recovery = false; @@ -1280,7 +1280,7 @@ intel_dp_start_link_train(struct intel_dp *intel_dp) static void intel_dp_complete_link_train(struct intel_dp *intel_dp) { - struct drm_device *dev = intel_dp->base.enc.dev; + struct drm_device *dev = intel_dp->base.base.dev; struct drm_i915_private *dev_priv = dev->dev_private; bool channel_eq = false; int tries; @@ -1345,7 +1345,7 @@ intel_dp_complete_link_train(struct intel_dp *intel_dp) static void intel_dp_link_down(struct intel_dp *intel_dp) { - struct drm_device *dev = intel_dp->base.enc.dev; + struct drm_device *dev = intel_dp->base.base.dev; struct drm_i915_private *dev_priv = dev->dev_private; uint32_t DP = intel_dp->DP; @@ -1388,7 +1388,7 @@ intel_dp_link_down(struct intel_dp *intel_dp) static void intel_dp_check_link_status(struct intel_dp *intel_dp) { - if (!intel_dp->base.enc.crtc) + if (!intel_dp->base.base.crtc) return; if (!intel_dp_get_link_status(intel_dp)) { @@ -1438,7 +1438,7 @@ intel_dp_detect(struct drm_connector *connector) { struct drm_encoder *encoder = intel_attached_encoder(connector); struct intel_dp *intel_dp = enc_to_intel_dp(encoder); - struct drm_device *dev = intel_dp->base.enc.dev; + struct drm_device *dev = intel_dp->base.base.dev; struct drm_i915_private *dev_priv = dev->dev_private; uint32_t temp, bit; enum drm_connector_status status; @@ -1482,7 +1482,7 @@ static int intel_dp_get_modes(struct drm_connector *connector) { struct drm_encoder *encoder = intel_attached_encoder(connector); struct intel_dp *intel_dp = enc_to_intel_dp(encoder); - struct drm_device *dev = intel_dp->base.enc.dev; + struct drm_device *dev = intel_dp->base.base.dev; struct drm_i915_private *dev_priv = dev->dev_private; int ret; @@ -1670,12 +1670,12 @@ intel_dp_init(struct drm_device *dev, int output_reg) intel_dp->has_audio = false; intel_dp->dpms_mode = DRM_MODE_DPMS_ON; - drm_encoder_init(dev, &intel_encoder->enc, &intel_dp_enc_funcs, + drm_encoder_init(dev, &intel_encoder->base, &intel_dp_enc_funcs, DRM_MODE_ENCODER_TMDS); - drm_encoder_helper_add(&intel_encoder->enc, &intel_dp_helper_funcs); + drm_encoder_helper_add(&intel_encoder->base, &intel_dp_helper_funcs); drm_mode_connector_attach_encoder(&intel_connector->base, - &intel_encoder->enc); + &intel_encoder->base); drm_sysfs_connector_add(connector); /* Set up the DDC bus. */ diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index b454d1a..454bcf3 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -137,7 +137,7 @@ struct intel_fbdev { }; struct intel_encoder { - struct drm_encoder enc; + struct drm_encoder base; int type; struct i2c_adapter *i2c_bus; struct i2c_adapter *ddc_bus; @@ -174,7 +174,7 @@ struct intel_crtc { #define to_intel_crtc(x) container_of(x, struct intel_crtc, base) #define to_intel_connector(x) container_of(x, struct intel_connector, base) -#define enc_to_intel_encoder(x) container_of(x, struct intel_encoder, enc) +#define to_intel_encoder(x) container_of(x, struct intel_encoder, base) #define to_intel_framebuffer(x) container_of(x, struct intel_framebuffer, base) struct intel_unpin_work { diff --git a/drivers/gpu/drm/i915/intel_dvo.c b/drivers/gpu/drm/i915/intel_dvo.c index a399f4b..7bf7311 100644 --- a/drivers/gpu/drm/i915/intel_dvo.c +++ b/drivers/gpu/drm/i915/intel_dvo.c @@ -88,7 +88,7 @@ struct intel_dvo { static struct intel_dvo *enc_to_intel_dvo(struct drm_encoder *encoder) { - return container_of(enc_to_intel_encoder(encoder), struct intel_dvo, base); + return container_of(encoder, struct intel_dvo, base.base); } static void intel_dvo_dpms(struct drm_encoder *encoder, int mode) @@ -426,13 +426,13 @@ void intel_dvo_init(struct drm_device *dev) connector->interlace_allowed = false; connector->doublescan_allowed = false; - drm_encoder_init(dev, &intel_encoder->enc, + drm_encoder_init(dev, &intel_encoder->base, &intel_dvo_enc_funcs, encoder_type); - drm_encoder_helper_add(&intel_encoder->enc, + drm_encoder_helper_add(&intel_encoder->base, &intel_dvo_helper_funcs); drm_mode_connector_attach_encoder(&intel_connector->base, - &intel_encoder->enc); + &intel_encoder->base); if (dvo->type == INTEL_DVO_CHIP_LVDS) { /* For our LVDS chipsets, we should hopefully be able * to dig the fixed panel mode out of the BIOS data. diff --git a/drivers/gpu/drm/i915/intel_hdmi.c b/drivers/gpu/drm/i915/intel_hdmi.c index ccd4c97..405afd7 100644 --- a/drivers/gpu/drm/i915/intel_hdmi.c +++ b/drivers/gpu/drm/i915/intel_hdmi.c @@ -45,7 +45,7 @@ struct intel_hdmi { static struct intel_hdmi *enc_to_intel_hdmi(struct drm_encoder *encoder) { - return container_of(enc_to_intel_encoder(encoder), struct intel_hdmi, base); + return container_of(encoder, struct intel_hdmi, base.base); } static void intel_hdmi_mode_set(struct drm_encoder *encoder, @@ -266,12 +266,12 @@ void intel_hdmi_init(struct drm_device *dev, int sdvox_reg) intel_hdmi->sdvox_reg = sdvox_reg; - drm_encoder_init(dev, &intel_encoder->enc, &intel_hdmi_enc_funcs, + drm_encoder_init(dev, &intel_encoder->base, &intel_hdmi_enc_funcs, DRM_MODE_ENCODER_TMDS); - drm_encoder_helper_add(&intel_encoder->enc, &intel_hdmi_helper_funcs); + drm_encoder_helper_add(&intel_encoder->base, &intel_hdmi_helper_funcs); drm_mode_connector_attach_encoder(&intel_connector->base, - &intel_encoder->enc); + &intel_encoder->base); drm_sysfs_connector_add(connector); /* For G4X desktop chip, PEG_BAND_GAP_DATA 3:0 must first be written diff --git a/drivers/gpu/drm/i915/intel_lvds.c b/drivers/gpu/drm/i915/intel_lvds.c index ef64551..ed1c876 100644 --- a/drivers/gpu/drm/i915/intel_lvds.c +++ b/drivers/gpu/drm/i915/intel_lvds.c @@ -50,7 +50,7 @@ struct intel_lvds { static struct intel_lvds *enc_to_intel_lvds(struct drm_encoder *encoder) { - return container_of(enc_to_intel_encoder(encoder), struct intel_lvds, base); + return container_of(encoder, struct intel_lvds, base.base); } static void intel_lvds_lock_panel(struct drm_device *dev, bool lock) @@ -437,7 +437,7 @@ static int intel_lvds_get_modes(struct drm_connector *connector) { struct drm_device *dev = connector->dev; struct drm_encoder *encoder = intel_attached_encoder(connector); - struct intel_encoder *intel_encoder = enc_to_intel_encoder(encoder); + struct intel_encoder *intel_encoder = to_intel_encoder(encoder); struct drm_i915_private *dev_priv = dev->dev_private; int ret = 0; @@ -839,15 +839,15 @@ void intel_lvds_init(struct drm_device *dev) } intel_encoder = &intel_lvds->base; - encoder = &intel_encoder->enc; + encoder = &intel_encoder->base; connector = &intel_connector->base; drm_connector_init(dev, &intel_connector->base, &intel_lvds_connector_funcs, DRM_MODE_CONNECTOR_LVDS); - drm_encoder_init(dev, &intel_encoder->enc, &intel_lvds_enc_funcs, + drm_encoder_init(dev, &intel_encoder->base, &intel_lvds_enc_funcs, DRM_MODE_ENCODER_LVDS); - drm_mode_connector_attach_encoder(&intel_connector->base, &intel_encoder->enc); + drm_mode_connector_attach_encoder(&intel_connector->base, &intel_encoder->base); intel_encoder->type = INTEL_OUTPUT_LVDS; intel_encoder->clone_mask = (1 << INTEL_LVDS_CLONE_BIT); diff --git a/drivers/gpu/drm/i915/intel_modes.c b/drivers/gpu/drm/i915/intel_modes.c index 4b1fd3d..1138aa9 100644 --- a/drivers/gpu/drm/i915/intel_modes.c +++ b/drivers/gpu/drm/i915/intel_modes.c @@ -54,9 +54,9 @@ bool intel_ddc_probe(struct intel_encoder *intel_encoder) } }; - intel_i2c_quirk_set(intel_encoder->enc.dev, true); + intel_i2c_quirk_set(intel_encoder->base.dev, true); ret = i2c_transfer(intel_encoder->ddc_bus, msgs, 2); - intel_i2c_quirk_set(intel_encoder->enc.dev, false); + intel_i2c_quirk_set(intel_encoder->base.dev, false); if (ret == 2) return true; diff --git a/drivers/gpu/drm/i915/intel_sdvo.c b/drivers/gpu/drm/i915/intel_sdvo.c index 1c1aeea..3d8f4f4 100644 --- a/drivers/gpu/drm/i915/intel_sdvo.c +++ b/drivers/gpu/drm/i915/intel_sdvo.c @@ -186,7 +186,7 @@ struct intel_sdvo_connector { static struct intel_sdvo *enc_to_intel_sdvo(struct drm_encoder *encoder) { - return container_of(enc_to_intel_encoder(encoder), struct intel_sdvo, base); + return container_of(encoder, struct intel_sdvo, base.base); } static struct intel_sdvo_connector *to_intel_sdvo_connector(struct drm_connector *connector) @@ -211,7 +211,7 @@ intel_sdvo_create_enhance_property(struct intel_sdvo *intel_sdvo, */ static void intel_sdvo_write_sdvox(struct intel_sdvo *intel_sdvo, u32 val) { - struct drm_device *dev = intel_sdvo->base.enc.dev; + struct drm_device *dev = intel_sdvo->base.base.dev; struct drm_i915_private *dev_priv = dev->dev_private; u32 bval = val, cval = val; int i; @@ -2077,7 +2077,7 @@ intel_sdvo_connector_init(struct drm_encoder *encoder, static bool intel_sdvo_dvi_init(struct intel_sdvo *intel_sdvo, int device) { - struct drm_encoder *encoder = &intel_sdvo->base.enc; + struct drm_encoder *encoder = &intel_sdvo->base.base; struct drm_connector *connector; struct intel_connector *intel_connector; struct intel_sdvo_connector *intel_sdvo_connector; @@ -2120,36 +2120,36 @@ intel_sdvo_dvi_init(struct intel_sdvo *intel_sdvo, int device) static bool intel_sdvo_tv_init(struct intel_sdvo *intel_sdvo, int type) { - struct drm_encoder *encoder = &intel_sdvo->base.enc; - struct drm_connector *connector; - struct intel_connector *intel_connector; - struct intel_sdvo_connector *intel_sdvo_connector; + struct drm_encoder *encoder = &intel_sdvo->base.base; + struct drm_connector *connector; + struct intel_connector *intel_connector; + struct intel_sdvo_connector *intel_sdvo_connector; intel_sdvo_connector = kzalloc(sizeof(struct intel_sdvo_connector), GFP_KERNEL); if (!intel_sdvo_connector) return false; intel_connector = &intel_sdvo_connector->base; - connector = &intel_connector->base; - encoder->encoder_type = DRM_MODE_ENCODER_TVDAC; - connector->connector_type = DRM_MODE_CONNECTOR_SVIDEO; + connector = &intel_connector->base; + encoder->encoder_type = DRM_MODE_ENCODER_TVDAC; + connector->connector_type = DRM_MODE_CONNECTOR_SVIDEO; - intel_sdvo->controlled_output |= type; - intel_sdvo_connector->output_flag = type; + intel_sdvo->controlled_output |= type; + intel_sdvo_connector->output_flag = type; - intel_sdvo->is_tv = true; - intel_sdvo->base.needs_tv_clock = true; - intel_sdvo->base.clone_mask = 1 << INTEL_SDVO_TV_CLONE_BIT; + intel_sdvo->is_tv = true; + intel_sdvo->base.needs_tv_clock = true; + intel_sdvo->base.clone_mask = 1 << INTEL_SDVO_TV_CLONE_BIT; - intel_sdvo_connector_init(encoder, connector); + intel_sdvo_connector_init(encoder, connector); - if (!intel_sdvo_tv_create_property(intel_sdvo, intel_sdvo_connector, type)) + if (!intel_sdvo_tv_create_property(intel_sdvo, intel_sdvo_connector, type)) goto err; - if (!intel_sdvo_create_enhance_property(intel_sdvo, intel_sdvo_connector)) + if (!intel_sdvo_create_enhance_property(intel_sdvo, intel_sdvo_connector)) goto err; - return true; + return true; err: intel_sdvo_destroy_enhance_property(connector); @@ -2160,43 +2160,43 @@ err: static bool intel_sdvo_analog_init(struct intel_sdvo *intel_sdvo, int device) { - struct drm_encoder *encoder = &intel_sdvo->base.enc; - struct drm_connector *connector; - struct intel_connector *intel_connector; - struct intel_sdvo_connector *intel_sdvo_connector; + struct drm_encoder *encoder = &intel_sdvo->base.base; + struct drm_connector *connector; + struct intel_connector *intel_connector; + struct intel_sdvo_connector *intel_sdvo_connector; intel_sdvo_connector = kzalloc(sizeof(struct intel_sdvo_connector), GFP_KERNEL); if (!intel_sdvo_connector) return false; intel_connector = &intel_sdvo_connector->base; - connector = &intel_connector->base; + connector = &intel_connector->base; connector->polled = DRM_CONNECTOR_POLL_CONNECT; - encoder->encoder_type = DRM_MODE_ENCODER_DAC; - connector->connector_type = DRM_MODE_CONNECTOR_VGA; - - if (device == 0) { - intel_sdvo->controlled_output |= SDVO_OUTPUT_RGB0; - intel_sdvo_connector->output_flag = SDVO_OUTPUT_RGB0; - } else if (device == 1) { - intel_sdvo->controlled_output |= SDVO_OUTPUT_RGB1; - intel_sdvo_connector->output_flag = SDVO_OUTPUT_RGB1; - } - - intel_sdvo->base.clone_mask = ((1 << INTEL_SDVO_NON_TV_CLONE_BIT) | + encoder->encoder_type = DRM_MODE_ENCODER_DAC; + connector->connector_type = DRM_MODE_CONNECTOR_VGA; + + if (device == 0) { + intel_sdvo->controlled_output |= SDVO_OUTPUT_RGB0; + intel_sdvo_connector->output_flag = SDVO_OUTPUT_RGB0; + } else if (device == 1) { + intel_sdvo->controlled_output |= SDVO_OUTPUT_RGB1; + intel_sdvo_connector->output_flag = SDVO_OUTPUT_RGB1; + } + + intel_sdvo->base.clone_mask = ((1 << INTEL_SDVO_NON_TV_CLONE_BIT) | (1 << INTEL_ANALOG_CLONE_BIT)); - intel_sdvo_connector_init(encoder, connector); - return true; + intel_sdvo_connector_init(encoder, connector); + return true; } static bool intel_sdvo_lvds_init(struct intel_sdvo *intel_sdvo, int device) { - struct drm_encoder *encoder = &intel_sdvo->base.enc; - struct drm_connector *connector; - struct intel_connector *intel_connector; - struct intel_sdvo_connector *intel_sdvo_connector; + struct drm_encoder *encoder = &intel_sdvo->base.base; + struct drm_connector *connector; + struct intel_connector *intel_connector; + struct intel_sdvo_connector *intel_sdvo_connector; intel_sdvo_connector = kzalloc(sizeof(struct intel_sdvo_connector), GFP_KERNEL); if (!intel_sdvo_connector) @@ -2204,22 +2204,22 @@ intel_sdvo_lvds_init(struct intel_sdvo *intel_sdvo, int device) intel_connector = &intel_sdvo_connector->base; connector = &intel_connector->base; - encoder->encoder_type = DRM_MODE_ENCODER_LVDS; - connector->connector_type = DRM_MODE_CONNECTOR_LVDS; - - if (device == 0) { - intel_sdvo->controlled_output |= SDVO_OUTPUT_LVDS0; - intel_sdvo_connector->output_flag = SDVO_OUTPUT_LVDS0; - } else if (device == 1) { - intel_sdvo->controlled_output |= SDVO_OUTPUT_LVDS1; - intel_sdvo_connector->output_flag = SDVO_OUTPUT_LVDS1; - } - - intel_sdvo->base.clone_mask = ((1 << INTEL_ANALOG_CLONE_BIT) | + encoder->encoder_type = DRM_MODE_ENCODER_LVDS; + connector->connector_type = DRM_MODE_CONNECTOR_LVDS; + + if (device == 0) { + intel_sdvo->controlled_output |= SDVO_OUTPUT_LVDS0; + intel_sdvo_connector->output_flag = SDVO_OUTPUT_LVDS0; + } else if (device == 1) { + intel_sdvo->controlled_output |= SDVO_OUTPUT_LVDS1; + intel_sdvo_connector->output_flag = SDVO_OUTPUT_LVDS1; + } + + intel_sdvo->base.clone_mask = ((1 << INTEL_ANALOG_CLONE_BIT) | (1 << INTEL_SDVO_LVDS_CLONE_BIT)); - intel_sdvo_connector_init(encoder, connector); - if (!intel_sdvo_create_enhance_property(intel_sdvo, intel_sdvo_connector)) + intel_sdvo_connector_init(encoder, connector); + if (!intel_sdvo_create_enhance_property(intel_sdvo, intel_sdvo_connector)) goto err; return true; @@ -2291,7 +2291,7 @@ static bool intel_sdvo_tv_create_property(struct intel_sdvo *intel_sdvo, struct intel_sdvo_connector *intel_sdvo_connector, int type) { - struct drm_device *dev = intel_sdvo->base.enc.dev; + struct drm_device *dev = intel_sdvo->base.base.dev; struct intel_sdvo_tv_format format; uint32_t format_map, i; @@ -2357,7 +2357,7 @@ intel_sdvo_create_enhance_property_tv(struct intel_sdvo *intel_sdvo, struct intel_sdvo_connector *intel_sdvo_connector, struct intel_sdvo_enhancements_reply enhancements) { - struct drm_device *dev = intel_sdvo->base.enc.dev; + struct drm_device *dev = intel_sdvo->base.base.dev; struct drm_connector *connector = &intel_sdvo_connector->base.base; uint16_t response, data_value[2]; @@ -2486,7 +2486,7 @@ intel_sdvo_create_enhance_property_lvds(struct intel_sdvo *intel_sdvo, struct intel_sdvo_connector *intel_sdvo_connector, struct intel_sdvo_enhancements_reply enhancements) { - struct drm_device *dev = intel_sdvo->base.enc.dev; + struct drm_device *dev = intel_sdvo->base.base.dev; struct drm_connector *connector = &intel_sdvo_connector->base.base; uint16_t response, data_value[2]; @@ -2593,8 +2593,8 @@ bool intel_sdvo_init(struct drm_device *dev, int sdvo_reg) intel_encoder->ddc_bus->algo = &intel_sdvo_i2c_bit_algo; /* encoder type will be decided later */ - drm_encoder_init(dev, &intel_encoder->enc, &intel_sdvo_enc_funcs, 0); - drm_encoder_helper_add(&intel_encoder->enc, &intel_sdvo_helper_funcs); + drm_encoder_init(dev, &intel_encoder->base, &intel_sdvo_enc_funcs, 0); + drm_encoder_helper_add(&intel_encoder->base, &intel_sdvo_helper_funcs); /* In default case sdvo lvds is false */ if (!intel_sdvo_get_capabilities(intel_sdvo, &intel_sdvo->caps)) @@ -2637,7 +2637,7 @@ bool intel_sdvo_init(struct drm_device *dev, int sdvo_reg) return true; err_enc: - drm_encoder_cleanup(&intel_encoder->enc); + drm_encoder_cleanup(&intel_encoder->base); err_i2c: if (intel_sdvo->analog_ddc_bus != NULL) intel_i2c_destroy(intel_sdvo->analog_ddc_bus); diff --git a/drivers/gpu/drm/i915/intel_tv.c b/drivers/gpu/drm/i915/intel_tv.c index d406672..12f15cb 100644 --- a/drivers/gpu/drm/i915/intel_tv.c +++ b/drivers/gpu/drm/i915/intel_tv.c @@ -900,7 +900,7 @@ static const struct tv_mode tv_modes[] = { static struct intel_tv *enc_to_intel_tv(struct drm_encoder *encoder) { - return container_of(enc_to_intel_encoder(encoder), struct intel_tv, base); + return container_of(encoder, struct intel_tv, base.base); } static void @@ -1230,7 +1230,7 @@ static const struct drm_display_mode reported_modes[] = { static int intel_tv_detect_type (struct intel_tv *intel_tv) { - struct drm_encoder *encoder = &intel_tv->base.enc; + struct drm_encoder *encoder = &intel_tv->base.base; struct drm_device *dev = encoder->dev; struct drm_i915_private *dev_priv = dev->dev_private; unsigned long irqflags; @@ -1656,15 +1656,16 @@ intel_tv_init(struct drm_device *dev) drm_connector_init(dev, connector, &intel_tv_connector_funcs, DRM_MODE_CONNECTOR_SVIDEO); - drm_encoder_init(dev, &intel_encoder->enc, &intel_tv_enc_funcs, + drm_encoder_init(dev, &intel_encoder->base, &intel_tv_enc_funcs, DRM_MODE_ENCODER_TVDAC); - drm_mode_connector_attach_encoder(&intel_connector->base, &intel_encoder->enc); + drm_mode_connector_attach_encoder(&intel_connector->base, + &intel_encoder->base); intel_encoder->type = INTEL_OUTPUT_TVOUT; intel_encoder->crtc_mask = (1 << 0) | (1 << 1); intel_encoder->clone_mask = (1 << INTEL_TV_CLONE_BIT); - intel_encoder->enc.possible_crtcs = ((1 << 0) | (1 << 1)); - intel_encoder->enc.possible_clones = (1 << INTEL_OUTPUT_TVOUT); + intel_encoder->base.possible_crtcs = ((1 << 0) | (1 << 1)); + intel_encoder->base.possible_clones = (1 << INTEL_OUTPUT_TVOUT); intel_tv->type = DRM_MODE_CONNECTOR_Unknown; /* BIOS margin values */ @@ -1675,7 +1676,7 @@ intel_tv_init(struct drm_device *dev) intel_tv->tv_format = tv_modes[initial_mode].name; - drm_encoder_helper_add(&intel_encoder->enc, &intel_tv_helper_funcs); + drm_encoder_helper_add(&intel_encoder->base, &intel_tv_helper_funcs); drm_connector_helper_add(connector, &intel_tv_connector_helper_funcs); connector->interlace_allowed = false; connector->doublescan_allowed = false; -- cgit v1.1 From f875c15a4fbf37534dda30771d8bde8604fbbf09 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Thu, 9 Sep 2010 15:44:14 +0100 Subject: drm/i915: Use the direct mapping of pipe->crtc Why iterate all the crtcs to find the pipe, when we already know which crtc is attached to which pipe? Signed-off-by: Chris Wilson Reviewed-by: Jesse Barnes --- drivers/gpu/drm/i915/intel_display.c | 12 ------------ drivers/gpu/drm/i915/intel_drv.h | 8 +++++++- drivers/gpu/drm/i915/intel_dvo.c | 2 +- drivers/gpu/drm/i915/intel_lvds.c | 2 +- 4 files changed, 9 insertions(+), 15 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 24c7b0e..7e67bf5 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -5226,18 +5226,6 @@ int intel_get_pipe_from_crtc_id(struct drm_device *dev, void *data, return 0; } -struct drm_crtc *intel_get_crtc_from_pipe(struct drm_device *dev, int pipe) -{ - struct drm_crtc *crtc = NULL; - - list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { - struct intel_crtc *intel_crtc = to_intel_crtc(crtc); - if (intel_crtc->pipe == pipe) - break; - } - return crtc; -} - static int intel_encoder_clones(struct drm_device *dev, int type_mask) { struct intel_encoder *encoder; diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index 454bcf3..ba94944 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -177,6 +177,13 @@ struct intel_crtc { #define to_intel_encoder(x) container_of(x, struct intel_encoder, base) #define to_intel_framebuffer(x) container_of(x, struct intel_framebuffer, base) +static inline struct drm_crtc * +intel_get_crtc_for_pipe(struct drm_device *dev, int pipe) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + return dev_priv->pipe_to_crtc_mapping[pipe]; +} + struct intel_unpin_work { struct work_struct work; struct drm_device *dev; @@ -235,7 +242,6 @@ int intel_get_pipe_from_crtc_id(struct drm_device *dev, void *data, struct drm_file *file_priv); extern void intel_wait_for_vblank_off(struct drm_device *dev, int pipe); extern void intel_wait_for_vblank(struct drm_device *dev, int pipe); -extern struct drm_crtc *intel_get_crtc_from_pipe(struct drm_device *dev, int pipe); extern struct drm_crtc *intel_get_load_detect_pipe(struct intel_encoder *intel_encoder, struct drm_connector *connector, struct drm_display_mode *mode, diff --git a/drivers/gpu/drm/i915/intel_dvo.c b/drivers/gpu/drm/i915/intel_dvo.c index 7bf7311..b15c9da 100644 --- a/drivers/gpu/drm/i915/intel_dvo.c +++ b/drivers/gpu/drm/i915/intel_dvo.c @@ -322,7 +322,7 @@ intel_dvo_get_current_mode(struct drm_connector *connector) struct drm_crtc *crtc; int pipe = (dvo_val & DVO_PIPE_B_SELECT) ? 1 : 0; - crtc = intel_get_crtc_from_pipe(dev, pipe); + crtc = intel_get_crtc_for_pipe(dev, pipe); if (crtc) { mode = intel_crtc_mode_get(dev, crtc); if (mode) { diff --git a/drivers/gpu/drm/i915/intel_lvds.c b/drivers/gpu/drm/i915/intel_lvds.c index ed1c876..987973f 100644 --- a/drivers/gpu/drm/i915/intel_lvds.c +++ b/drivers/gpu/drm/i915/intel_lvds.c @@ -932,7 +932,7 @@ void intel_lvds_init(struct drm_device *dev) lvds = I915_READ(LVDS); pipe = (lvds & LVDS_PIPEB_SELECT) ? 1 : 0; - crtc = intel_get_crtc_from_pipe(dev, pipe); + crtc = intel_get_crtc_for_pipe(dev, pipe); if (crtc && (lvds & LVDS_PORT_EN)) { dev_priv->panel_fixed_mode = intel_crtc_mode_get(dev, crtc); -- cgit v1.1 From df0e924883d029a8651a2a0c7b8da67a07611ed2 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Thu, 9 Sep 2010 16:20:55 +0100 Subject: drm/i915: Make the connector->encoder relationship explicit Currently we have a exact mapping of a connector onto an encoder for its whole lifetime. Make this an explicit property of the structure and so simplify the code. Signed-off-by: Chris Wilson Reviewed-by: Jesse Barnes --- drivers/gpu/drm/i915/intel_crt.c | 25 +++++------ drivers/gpu/drm/i915/intel_display.c | 27 ++++------- drivers/gpu/drm/i915/intel_dp.c | 23 +++++----- drivers/gpu/drm/i915/intel_drv.h | 10 ++++- drivers/gpu/drm/i915/intel_dvo.c | 24 +++++----- drivers/gpu/drm/i915/intel_hdmi.c | 17 ++++--- drivers/gpu/drm/i915/intel_lvds.c | 11 ++--- drivers/gpu/drm/i915/intel_sdvo.c | 86 +++++++++++++++++++----------------- drivers/gpu/drm/i915/intel_tv.c | 34 +++++++------- 9 files changed, 130 insertions(+), 127 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_crt.c b/drivers/gpu/drm/i915/intel_crt.c index e3f5e21..b39183b 100644 --- a/drivers/gpu/drm/i915/intel_crt.c +++ b/drivers/gpu/drm/i915/intel_crt.c @@ -404,8 +404,7 @@ intel_crt_load_detect(struct drm_crtc *crtc, struct intel_encoder *intel_encoder static enum drm_connector_status intel_crt_detect(struct drm_connector *connector) { struct drm_device *dev = connector->dev; - struct drm_encoder *encoder = intel_attached_encoder(connector); - struct intel_encoder *intel_encoder = to_intel_encoder(encoder); + struct intel_encoder *encoder = intel_attached_encoder(connector); struct drm_crtc *crtc; int dpms_mode; enum drm_connector_status status; @@ -417,18 +416,18 @@ static enum drm_connector_status intel_crt_detect(struct drm_connector *connecto return connector_status_disconnected; } - if (intel_crt_detect_ddc(encoder)) + if (intel_crt_detect_ddc(&encoder->base)) return connector_status_connected; /* for pre-945g platforms use load detect */ - if (encoder->crtc && encoder->crtc->enabled) { - status = intel_crt_load_detect(encoder->crtc, intel_encoder); + if (encoder->base.crtc && encoder->base.crtc->enabled) { + status = intel_crt_load_detect(encoder->base.crtc, encoder); } else { - crtc = intel_get_load_detect_pipe(intel_encoder, connector, + crtc = intel_get_load_detect_pipe(encoder, connector, NULL, &dpms_mode); if (crtc) { - status = intel_crt_load_detect(crtc, intel_encoder); - intel_release_load_detect_pipe(intel_encoder, + status = intel_crt_load_detect(crtc, encoder); + intel_release_load_detect_pipe(encoder, connector, dpms_mode); } else status = connector_status_unknown; @@ -447,13 +446,12 @@ static void intel_crt_destroy(struct drm_connector *connector) static int intel_crt_get_modes(struct drm_connector *connector) { int ret; - struct drm_encoder *encoder = intel_attached_encoder(connector); - struct intel_encoder *intel_encoder = to_intel_encoder(encoder); + struct intel_encoder *encoder = intel_attached_encoder(connector); struct i2c_adapter *ddc_bus; struct drm_device *dev = connector->dev; - ret = intel_ddc_get_modes(connector, intel_encoder->ddc_bus); + ret = intel_ddc_get_modes(connector, encoder->ddc_bus); if (ret || !IS_G4X(dev)) goto end; @@ -504,7 +502,7 @@ static const struct drm_connector_funcs intel_crt_connector_funcs = { static const struct drm_connector_helper_funcs intel_crt_connector_helper_funcs = { .mode_valid = intel_crt_mode_valid, .get_modes = intel_crt_get_modes, - .best_encoder = intel_attached_encoder, + .best_encoder = intel_best_encoder, }; static const struct drm_encoder_funcs intel_crt_enc_funcs = { @@ -536,8 +534,7 @@ void intel_crt_init(struct drm_device *dev) drm_encoder_init(dev, &intel_encoder->base, &intel_crt_enc_funcs, DRM_MODE_ENCODER_DAC); - drm_mode_connector_attach_encoder(&intel_connector->base, - &intel_encoder->base); + intel_connector_attach_encoder(intel_connector, intel_encoder); /* Set up the DDC bus. */ if (HAS_PCH_SPLIT(dev)) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 7e67bf5..a9df278 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -6120,26 +6120,17 @@ void intel_modeset_cleanup(struct drm_device *dev) /* * Return which encoder is currently attached for connector. */ -struct drm_encoder *intel_attached_encoder (struct drm_connector *connector) +struct drm_encoder *intel_best_encoder(struct drm_connector *connector) { - struct drm_mode_object *obj; - struct drm_encoder *encoder; - int i; - - for (i = 0; i < DRM_CONNECTOR_MAX_ENCODER; i++) { - if (connector->encoder_ids[i] == 0) - break; - - obj = drm_mode_object_find(connector->dev, - connector->encoder_ids[i], - DRM_MODE_OBJECT_ENCODER); - if (!obj) - continue; + return &intel_attached_encoder(connector)->base; +} - encoder = obj_to_encoder(obj); - return encoder; - } - return NULL; +void intel_connector_attach_encoder(struct intel_connector *connector, + struct intel_encoder *encoder) +{ + connector->encoder = encoder; + drm_mode_connector_attach_encoder(&connector->base, + &encoder->base); } /* diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c index 6cdc53d..b9efeaf 100644 --- a/drivers/gpu/drm/i915/intel_dp.c +++ b/drivers/gpu/drm/i915/intel_dp.c @@ -67,6 +67,12 @@ static struct intel_dp *enc_to_intel_dp(struct drm_encoder *encoder) return container_of(encoder, struct intel_dp, base.base); } +static struct intel_dp *intel_attached_dp(struct drm_connector *connector) +{ + return container_of(intel_attached_encoder(connector), + struct intel_dp, base); +} + static void intel_dp_start_link_train(struct intel_dp *intel_dp); static void intel_dp_complete_link_train(struct intel_dp *intel_dp); static void intel_dp_link_down(struct intel_dp *intel_dp); @@ -148,8 +154,7 @@ static int intel_dp_mode_valid(struct drm_connector *connector, struct drm_display_mode *mode) { - struct drm_encoder *encoder = intel_attached_encoder(connector); - struct intel_dp *intel_dp = enc_to_intel_dp(encoder); + struct intel_dp *intel_dp = intel_attached_dp(connector); struct drm_device *dev = connector->dev; struct drm_i915_private *dev_priv = dev->dev_private; int max_link_clock = intel_dp_link_clock(intel_dp_max_link_bw(intel_dp)); @@ -1405,8 +1410,7 @@ intel_dp_check_link_status(struct intel_dp *intel_dp) static enum drm_connector_status ironlake_dp_detect(struct drm_connector *connector) { - struct drm_encoder *encoder = intel_attached_encoder(connector); - struct intel_dp *intel_dp = enc_to_intel_dp(encoder); + struct intel_dp *intel_dp = intel_attached_dp(connector); enum drm_connector_status status; /* Panel needs power for AUX to work */ @@ -1436,8 +1440,7 @@ ironlake_dp_detect(struct drm_connector *connector) static enum drm_connector_status intel_dp_detect(struct drm_connector *connector) { - struct drm_encoder *encoder = intel_attached_encoder(connector); - struct intel_dp *intel_dp = enc_to_intel_dp(encoder); + struct intel_dp *intel_dp = intel_attached_dp(connector); struct drm_device *dev = intel_dp->base.base.dev; struct drm_i915_private *dev_priv = dev->dev_private; uint32_t temp, bit; @@ -1480,8 +1483,7 @@ intel_dp_detect(struct drm_connector *connector) static int intel_dp_get_modes(struct drm_connector *connector) { - struct drm_encoder *encoder = intel_attached_encoder(connector); - struct intel_dp *intel_dp = enc_to_intel_dp(encoder); + struct intel_dp *intel_dp = intel_attached_dp(connector); struct drm_device *dev = intel_dp->base.base.dev; struct drm_i915_private *dev_priv = dev->dev_private; int ret; @@ -1554,7 +1556,7 @@ static const struct drm_connector_funcs intel_dp_connector_funcs = { static const struct drm_connector_helper_funcs intel_dp_connector_helper_funcs = { .get_modes = intel_dp_get_modes, .mode_valid = intel_dp_mode_valid, - .best_encoder = intel_attached_encoder, + .best_encoder = intel_best_encoder, }; static const struct drm_encoder_funcs intel_dp_enc_funcs = { @@ -1674,8 +1676,7 @@ intel_dp_init(struct drm_device *dev, int output_reg) DRM_MODE_ENCODER_TMDS); drm_encoder_helper_add(&intel_encoder->base, &intel_dp_helper_funcs); - drm_mode_connector_attach_encoder(&intel_connector->base, - &intel_encoder->base); + intel_connector_attach_encoder(intel_connector, intel_encoder); drm_sysfs_connector_add(connector); /* Set up the DDC bus. */ diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index ba94944..1ada684 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -150,6 +150,7 @@ struct intel_encoder { struct intel_connector { struct drm_connector base; + struct intel_encoder *encoder; }; struct intel_crtc { @@ -234,7 +235,14 @@ extern void intel_encoder_prepare (struct drm_encoder *encoder); extern void intel_encoder_commit (struct drm_encoder *encoder); extern void intel_encoder_destroy(struct drm_encoder *encoder); -extern struct drm_encoder *intel_attached_encoder(struct drm_connector *connector); +static inline struct intel_encoder *intel_attached_encoder(struct drm_connector *connector) +{ + return to_intel_connector(connector)->encoder; +} + +extern void intel_connector_attach_encoder(struct intel_connector *connector, + struct intel_encoder *encoder); +extern struct drm_encoder *intel_best_encoder(struct drm_connector *connector); extern struct drm_display_mode *intel_crtc_mode_get(struct drm_device *dev, struct drm_crtc *crtc); diff --git a/drivers/gpu/drm/i915/intel_dvo.c b/drivers/gpu/drm/i915/intel_dvo.c index b15c9da..df42a9c 100644 --- a/drivers/gpu/drm/i915/intel_dvo.c +++ b/drivers/gpu/drm/i915/intel_dvo.c @@ -91,6 +91,12 @@ static struct intel_dvo *enc_to_intel_dvo(struct drm_encoder *encoder) return container_of(encoder, struct intel_dvo, base.base); } +static struct intel_dvo *intel_attached_dvo(struct drm_connector *connector) +{ + return container_of(intel_attached_encoder(connector), + struct intel_dvo, base); +} + static void intel_dvo_dpms(struct drm_encoder *encoder, int mode) { struct drm_i915_private *dev_priv = encoder->dev->dev_private; @@ -112,8 +118,7 @@ static void intel_dvo_dpms(struct drm_encoder *encoder, int mode) static int intel_dvo_mode_valid(struct drm_connector *connector, struct drm_display_mode *mode) { - struct drm_encoder *encoder = intel_attached_encoder(connector); - struct intel_dvo *intel_dvo = enc_to_intel_dvo(encoder); + struct intel_dvo *intel_dvo = intel_attached_dvo(connector); if (mode->flags & DRM_MODE_FLAG_DBLSCAN) return MODE_NO_DBLESCAN; @@ -223,16 +228,13 @@ static void intel_dvo_mode_set(struct drm_encoder *encoder, */ static enum drm_connector_status intel_dvo_detect(struct drm_connector *connector) { - struct drm_encoder *encoder = intel_attached_encoder(connector); - struct intel_dvo *intel_dvo = enc_to_intel_dvo(encoder); - + struct intel_dvo *intel_dvo = intel_attached_dvo(connector); return intel_dvo->dev.dev_ops->detect(&intel_dvo->dev); } static int intel_dvo_get_modes(struct drm_connector *connector) { - struct drm_encoder *encoder = intel_attached_encoder(connector); - struct intel_dvo *intel_dvo = enc_to_intel_dvo(encoder); + struct intel_dvo *intel_dvo = intel_attached_dvo(connector); /* We should probably have an i2c driver get_modes function for those * devices which will have a fixed set of modes determined by the chip @@ -280,7 +282,7 @@ static const struct drm_connector_funcs intel_dvo_connector_funcs = { static const struct drm_connector_helper_funcs intel_dvo_connector_helper_funcs = { .mode_valid = intel_dvo_mode_valid, .get_modes = intel_dvo_get_modes, - .best_encoder = intel_attached_encoder, + .best_encoder = intel_best_encoder, }; static void intel_dvo_enc_destroy(struct drm_encoder *encoder) @@ -310,8 +312,7 @@ intel_dvo_get_current_mode(struct drm_connector *connector) { struct drm_device *dev = connector->dev; struct drm_i915_private *dev_priv = dev->dev_private; - struct drm_encoder *encoder = intel_attached_encoder(connector); - struct intel_dvo *intel_dvo = enc_to_intel_dvo(encoder); + struct intel_dvo *intel_dvo = intel_attached_dvo(connector); uint32_t dvo_val = I915_READ(intel_dvo->dev.dvo_reg); struct drm_display_mode *mode = NULL; @@ -431,8 +432,7 @@ void intel_dvo_init(struct drm_device *dev) drm_encoder_helper_add(&intel_encoder->base, &intel_dvo_helper_funcs); - drm_mode_connector_attach_encoder(&intel_connector->base, - &intel_encoder->base); + intel_connector_attach_encoder(intel_connector, intel_encoder); if (dvo->type == INTEL_DVO_CHIP_LVDS) { /* For our LVDS chipsets, we should hopefully be able * to dig the fixed panel mode out of the BIOS data. diff --git a/drivers/gpu/drm/i915/intel_hdmi.c b/drivers/gpu/drm/i915/intel_hdmi.c index 405afd7..bba0aba 100644 --- a/drivers/gpu/drm/i915/intel_hdmi.c +++ b/drivers/gpu/drm/i915/intel_hdmi.c @@ -48,6 +48,12 @@ static struct intel_hdmi *enc_to_intel_hdmi(struct drm_encoder *encoder) return container_of(encoder, struct intel_hdmi, base.base); } +static struct intel_hdmi *intel_attached_hdmi(struct drm_connector *connector) +{ + return container_of(intel_attached_encoder(connector), + struct intel_hdmi, base); +} + static void intel_hdmi_mode_set(struct drm_encoder *encoder, struct drm_display_mode *mode, struct drm_display_mode *adjusted_mode) @@ -141,8 +147,7 @@ static bool intel_hdmi_mode_fixup(struct drm_encoder *encoder, static enum drm_connector_status intel_hdmi_detect(struct drm_connector *connector) { - struct drm_encoder *encoder = intel_attached_encoder(connector); - struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(encoder); + struct intel_hdmi *intel_hdmi = intel_attached_hdmi(connector); struct edid *edid = NULL; enum drm_connector_status status = connector_status_disconnected; @@ -163,8 +168,7 @@ intel_hdmi_detect(struct drm_connector *connector) static int intel_hdmi_get_modes(struct drm_connector *connector) { - struct drm_encoder *encoder = intel_attached_encoder(connector); - struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(encoder); + struct intel_hdmi *intel_hdmi = intel_attached_hdmi(connector); /* We should parse the EDID data and find out if it's an HDMI sink so * we can send audio to it. @@ -198,7 +202,7 @@ static const struct drm_connector_funcs intel_hdmi_connector_funcs = { static const struct drm_connector_helper_funcs intel_hdmi_connector_helper_funcs = { .get_modes = intel_hdmi_get_modes, .mode_valid = intel_hdmi_mode_valid, - .best_encoder = intel_attached_encoder, + .best_encoder = intel_best_encoder, }; static const struct drm_encoder_funcs intel_hdmi_enc_funcs = { @@ -270,8 +274,7 @@ void intel_hdmi_init(struct drm_device *dev, int sdvox_reg) DRM_MODE_ENCODER_TMDS); drm_encoder_helper_add(&intel_encoder->base, &intel_hdmi_helper_funcs); - drm_mode_connector_attach_encoder(&intel_connector->base, - &intel_encoder->base); + intel_connector_attach_encoder(intel_connector, intel_encoder); drm_sysfs_connector_add(connector); /* For G4X desktop chip, PEG_BAND_GAP_DATA 3:0 must first be written diff --git a/drivers/gpu/drm/i915/intel_lvds.c b/drivers/gpu/drm/i915/intel_lvds.c index 987973f..93a711d 100644 --- a/drivers/gpu/drm/i915/intel_lvds.c +++ b/drivers/gpu/drm/i915/intel_lvds.c @@ -436,14 +436,11 @@ static enum drm_connector_status intel_lvds_detect(struct drm_connector *connect static int intel_lvds_get_modes(struct drm_connector *connector) { struct drm_device *dev = connector->dev; - struct drm_encoder *encoder = intel_attached_encoder(connector); - struct intel_encoder *intel_encoder = to_intel_encoder(encoder); struct drm_i915_private *dev_priv = dev->dev_private; - int ret = 0; if (dev_priv->lvds_edid_good) { - ret = intel_ddc_get_modes(connector, intel_encoder->ddc_bus); - + struct intel_encoder *encoder = intel_attached_encoder(connector); + int ret = intel_ddc_get_modes(connector, encoder->ddc_bus); if (ret) return ret; } @@ -596,7 +593,7 @@ static const struct drm_encoder_helper_funcs intel_lvds_helper_funcs = { static const struct drm_connector_helper_funcs intel_lvds_connector_helper_funcs = { .get_modes = intel_lvds_get_modes, .mode_valid = intel_lvds_mode_valid, - .best_encoder = intel_attached_encoder, + .best_encoder = intel_best_encoder, }; static const struct drm_connector_funcs intel_lvds_connector_funcs = { @@ -847,7 +844,7 @@ void intel_lvds_init(struct drm_device *dev) drm_encoder_init(dev, &intel_encoder->base, &intel_lvds_enc_funcs, DRM_MODE_ENCODER_LVDS); - drm_mode_connector_attach_encoder(&intel_connector->base, &intel_encoder->base); + intel_connector_attach_encoder(intel_connector, intel_encoder); intel_encoder->type = INTEL_OUTPUT_LVDS; intel_encoder->clone_mask = (1 << INTEL_LVDS_CLONE_BIT); diff --git a/drivers/gpu/drm/i915/intel_sdvo.c b/drivers/gpu/drm/i915/intel_sdvo.c index 3d8f4f4..96952d2 100644 --- a/drivers/gpu/drm/i915/intel_sdvo.c +++ b/drivers/gpu/drm/i915/intel_sdvo.c @@ -189,6 +189,12 @@ static struct intel_sdvo *enc_to_intel_sdvo(struct drm_encoder *encoder) return container_of(encoder, struct intel_sdvo, base.base); } +static struct intel_sdvo *intel_attached_sdvo(struct drm_connector *connector) +{ + return container_of(intel_attached_encoder(connector), + struct intel_sdvo, base); +} + static struct intel_sdvo_connector *to_intel_sdvo_connector(struct drm_connector *connector) { return container_of(to_intel_connector(connector), struct intel_sdvo_connector, base); @@ -1239,8 +1245,7 @@ static void intel_sdvo_dpms(struct drm_encoder *encoder, int mode) static int intel_sdvo_mode_valid(struct drm_connector *connector, struct drm_display_mode *mode) { - struct drm_encoder *encoder = intel_attached_encoder(connector); - struct intel_sdvo *intel_sdvo = enc_to_intel_sdvo(encoder); + struct intel_sdvo *intel_sdvo = intel_attached_sdvo(connector); if (mode->flags & DRM_MODE_FLAG_DBLSCAN) return MODE_NO_DBLESCAN; @@ -1372,18 +1377,22 @@ static struct drm_connector * intel_find_analog_connector(struct drm_device *dev) { struct drm_connector *connector; - struct drm_encoder *encoder; - struct intel_sdvo *intel_sdvo; - - list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) { - intel_sdvo = enc_to_intel_sdvo(encoder); - if (intel_sdvo->base.type == INTEL_OUTPUT_ANALOG) { - list_for_each_entry(connector, &dev->mode_config.connector_list, head) { - if (encoder == intel_attached_encoder(connector)) + struct intel_sdvo *encoder; + + list_for_each_entry(encoder, + &dev->mode_config.encoder_list, + base.base.head) { + if (encoder->base.type == INTEL_OUTPUT_ANALOG) { + list_for_each_entry(connector, + &dev->mode_config.connector_list, + head) { + if (&encoder->base == + intel_attached_encoder(connector)) return connector; } } } + return NULL; } @@ -1406,8 +1415,7 @@ intel_analog_is_connected(struct drm_device *dev) enum drm_connector_status intel_sdvo_hdmi_sink_detect(struct drm_connector *connector) { - struct drm_encoder *encoder = intel_attached_encoder(connector); - struct intel_sdvo *intel_sdvo = enc_to_intel_sdvo(encoder); + struct intel_sdvo *intel_sdvo = intel_attached_sdvo(connector); struct intel_sdvo_connector *intel_sdvo_connector = to_intel_sdvo_connector(connector); enum drm_connector_status status = connector_status_connected; struct edid *edid = NULL; @@ -1468,8 +1476,7 @@ intel_sdvo_hdmi_sink_detect(struct drm_connector *connector) static enum drm_connector_status intel_sdvo_detect(struct drm_connector *connector) { uint16_t response; - struct drm_encoder *encoder = intel_attached_encoder(connector); - struct intel_sdvo *intel_sdvo = enc_to_intel_sdvo(encoder); + struct intel_sdvo *intel_sdvo = intel_attached_sdvo(connector); struct intel_sdvo_connector *intel_sdvo_connector = to_intel_sdvo_connector(connector); enum drm_connector_status ret; @@ -1516,8 +1523,7 @@ static enum drm_connector_status intel_sdvo_detect(struct drm_connector *connect static void intel_sdvo_get_ddc_modes(struct drm_connector *connector) { - struct drm_encoder *encoder = intel_attached_encoder(connector); - struct intel_sdvo *intel_sdvo = enc_to_intel_sdvo(encoder); + struct intel_sdvo *intel_sdvo = intel_attached_sdvo(connector); int num_modes; /* set the bus switch and get the modes */ @@ -1605,8 +1611,7 @@ struct drm_display_mode sdvo_tv_modes[] = { static void intel_sdvo_get_tv_modes(struct drm_connector *connector) { - struct drm_encoder *encoder = intel_attached_encoder(connector); - struct intel_sdvo *intel_sdvo = enc_to_intel_sdvo(encoder); + struct intel_sdvo *intel_sdvo = intel_attached_sdvo(connector); struct intel_sdvo_sdtv_resolution_request tv_res; uint32_t reply = 0, format_map = 0; int i; @@ -1640,8 +1645,7 @@ static void intel_sdvo_get_tv_modes(struct drm_connector *connector) static void intel_sdvo_get_lvds_modes(struct drm_connector *connector) { - struct drm_encoder *encoder = intel_attached_encoder(connector); - struct intel_sdvo *intel_sdvo = enc_to_intel_sdvo(encoder); + struct intel_sdvo *intel_sdvo = intel_attached_sdvo(connector); struct drm_i915_private *dev_priv = connector->dev->dev_private; struct drm_display_mode *newmode; @@ -1757,8 +1761,7 @@ intel_sdvo_set_property(struct drm_connector *connector, struct drm_property *property, uint64_t val) { - struct drm_encoder *encoder = intel_attached_encoder(connector); - struct intel_sdvo *intel_sdvo = enc_to_intel_sdvo(encoder); + struct intel_sdvo *intel_sdvo = intel_attached_sdvo(connector); struct intel_sdvo_connector *intel_sdvo_connector = to_intel_sdvo_connector(connector); uint16_t temp_value; uint8_t cmd; @@ -1861,9 +1864,8 @@ set_value: done: - if (encoder->crtc) { - struct drm_crtc *crtc = encoder->crtc; - + if (intel_sdvo->base.base.crtc) { + struct drm_crtc *crtc = intel_sdvo->base.base.crtc; drm_crtc_helper_set_mode(crtc, &crtc->mode, crtc->x, crtc->y, crtc->fb); } @@ -1891,7 +1893,7 @@ static const struct drm_connector_funcs intel_sdvo_connector_funcs = { static const struct drm_connector_helper_funcs intel_sdvo_connector_helper_funcs = { .get_modes = intel_sdvo_get_modes, .mode_valid = intel_sdvo_mode_valid, - .best_encoder = intel_attached_encoder, + .best_encoder = intel_best_encoder, }; static void intel_sdvo_enc_destroy(struct drm_encoder *encoder) @@ -2058,20 +2060,23 @@ intel_sdvo_get_slave_addr(struct drm_device *dev, int sdvo_reg) } static void -intel_sdvo_connector_init(struct drm_encoder *encoder, - struct drm_connector *connector) +intel_sdvo_connector_init(struct intel_sdvo_connector *connector, + struct intel_sdvo *encoder) { - drm_connector_init(encoder->dev, connector, &intel_sdvo_connector_funcs, - connector->connector_type); + drm_connector_init(encoder->base.base.dev, + &connector->base.base, + &intel_sdvo_connector_funcs, + connector->base.base.connector_type); - drm_connector_helper_add(connector, &intel_sdvo_connector_helper_funcs); + drm_connector_helper_add(&connector->base.base, + &intel_sdvo_connector_helper_funcs); - connector->interlace_allowed = 0; - connector->doublescan_allowed = 0; - connector->display_info.subpixel_order = SubPixelHorizontalRGB; + connector->base.base.interlace_allowed = 0; + connector->base.base.doublescan_allowed = 0; + connector->base.base.display_info.subpixel_order = SubPixelHorizontalRGB; - drm_mode_connector_attach_encoder(connector, encoder); - drm_sysfs_connector_add(connector); + intel_connector_attach_encoder(&connector->base, &encoder->base); + drm_sysfs_connector_add(&connector->base.base); } static bool @@ -2112,7 +2117,7 @@ intel_sdvo_dvi_init(struct intel_sdvo *intel_sdvo, int device) intel_sdvo->base.clone_mask = ((1 << INTEL_SDVO_NON_TV_CLONE_BIT) | (1 << INTEL_ANALOG_CLONE_BIT)); - intel_sdvo_connector_init(encoder, connector); + intel_sdvo_connector_init(intel_sdvo_connector, intel_sdvo); return true; } @@ -2141,7 +2146,7 @@ intel_sdvo_tv_init(struct intel_sdvo *intel_sdvo, int type) intel_sdvo->base.needs_tv_clock = true; intel_sdvo->base.clone_mask = 1 << INTEL_SDVO_TV_CLONE_BIT; - intel_sdvo_connector_init(encoder, connector); + intel_sdvo_connector_init(intel_sdvo_connector, intel_sdvo); if (!intel_sdvo_tv_create_property(intel_sdvo, intel_sdvo_connector, type)) goto err; @@ -2186,7 +2191,8 @@ intel_sdvo_analog_init(struct intel_sdvo *intel_sdvo, int device) intel_sdvo->base.clone_mask = ((1 << INTEL_SDVO_NON_TV_CLONE_BIT) | (1 << INTEL_ANALOG_CLONE_BIT)); - intel_sdvo_connector_init(encoder, connector); + intel_sdvo_connector_init(intel_sdvo_connector, + intel_sdvo); return true; } @@ -2218,7 +2224,7 @@ intel_sdvo_lvds_init(struct intel_sdvo *intel_sdvo, int device) intel_sdvo->base.clone_mask = ((1 << INTEL_ANALOG_CLONE_BIT) | (1 << INTEL_SDVO_LVDS_CLONE_BIT)); - intel_sdvo_connector_init(encoder, connector); + intel_sdvo_connector_init(intel_sdvo_connector, intel_sdvo); if (!intel_sdvo_create_enhance_property(intel_sdvo, intel_sdvo_connector)) goto err; diff --git a/drivers/gpu/drm/i915/intel_tv.c b/drivers/gpu/drm/i915/intel_tv.c index 12f15cb..267da32 100644 --- a/drivers/gpu/drm/i915/intel_tv.c +++ b/drivers/gpu/drm/i915/intel_tv.c @@ -903,6 +903,13 @@ static struct intel_tv *enc_to_intel_tv(struct drm_encoder *encoder) return container_of(encoder, struct intel_tv, base.base); } +static struct intel_tv *intel_attached_tv(struct drm_connector *connector) +{ + return container_of(intel_attached_encoder(connector), + struct intel_tv, + base); +} + static void intel_tv_dpms(struct drm_encoder *encoder, int mode) { @@ -945,8 +952,7 @@ static enum drm_mode_status intel_tv_mode_valid(struct drm_connector *connector, struct drm_display_mode *mode) { - struct drm_encoder *encoder = intel_attached_encoder(connector); - struct intel_tv *intel_tv = enc_to_intel_tv(encoder); + struct intel_tv *intel_tv = intel_attached_tv(connector); const struct tv_mode *tv_mode = intel_tv_mode_find(intel_tv); /* Ensure TV refresh is close to desired refresh */ @@ -1306,8 +1312,7 @@ intel_tv_detect_type (struct intel_tv *intel_tv) */ static void intel_tv_find_better_format(struct drm_connector *connector) { - struct drm_encoder *encoder = intel_attached_encoder(connector); - struct intel_tv *intel_tv = enc_to_intel_tv(encoder); + struct intel_tv *intel_tv = intel_attached_tv(connector); const struct tv_mode *tv_mode = intel_tv_mode_find(intel_tv); int i; @@ -1339,14 +1344,13 @@ static enum drm_connector_status intel_tv_detect(struct drm_connector *connector) { struct drm_display_mode mode; - struct drm_encoder *encoder = intel_attached_encoder(connector); - struct intel_tv *intel_tv = enc_to_intel_tv(encoder); + struct intel_tv *intel_tv = intel_attached_tv(connector); int type; mode = reported_modes[0]; drm_mode_set_crtcinfo(&mode, CRTC_INTERLACE_HALVE_V); - if (encoder->crtc && encoder->crtc->enabled) { + if (intel_tv->base.base.crtc && intel_tv->base.base.crtc->enabled) { type = intel_tv_detect_type(intel_tv); } else { struct drm_crtc *crtc; @@ -1391,8 +1395,7 @@ static void intel_tv_chose_preferred_modes(struct drm_connector *connector, struct drm_display_mode *mode_ptr) { - struct drm_encoder *encoder = intel_attached_encoder(connector); - struct intel_tv *intel_tv = enc_to_intel_tv(encoder); + struct intel_tv *intel_tv = intel_attached_tv(connector); const struct tv_mode *tv_mode = intel_tv_mode_find(intel_tv); if (tv_mode->nbr_end < 480 && mode_ptr->vdisplay == 480) @@ -1417,8 +1420,7 @@ static int intel_tv_get_modes(struct drm_connector *connector) { struct drm_display_mode *mode_ptr; - struct drm_encoder *encoder = intel_attached_encoder(connector); - struct intel_tv *intel_tv = enc_to_intel_tv(encoder); + struct intel_tv *intel_tv = intel_attached_tv(connector); const struct tv_mode *tv_mode = intel_tv_mode_find(intel_tv); int j, count = 0; u64 tmp; @@ -1483,9 +1485,8 @@ intel_tv_set_property(struct drm_connector *connector, struct drm_property *prop uint64_t val) { struct drm_device *dev = connector->dev; - struct drm_encoder *encoder = intel_attached_encoder(connector); - struct intel_tv *intel_tv = enc_to_intel_tv(encoder); - struct drm_crtc *crtc = encoder->crtc; + struct intel_tv *intel_tv = intel_attached_tv(connector); + struct drm_crtc *crtc = intel_tv->base.base.crtc; int ret = 0; bool changed = false; @@ -1550,7 +1551,7 @@ static const struct drm_connector_funcs intel_tv_connector_funcs = { static const struct drm_connector_helper_funcs intel_tv_connector_helper_funcs = { .mode_valid = intel_tv_mode_valid, .get_modes = intel_tv_get_modes, - .best_encoder = intel_attached_encoder, + .best_encoder = intel_best_encoder, }; static const struct drm_encoder_funcs intel_tv_enc_funcs = { @@ -1659,8 +1660,7 @@ intel_tv_init(struct drm_device *dev) drm_encoder_init(dev, &intel_encoder->base, &intel_tv_enc_funcs, DRM_MODE_ENCODER_TVDAC); - drm_mode_connector_attach_encoder(&intel_connector->base, - &intel_encoder->base); + intel_connector_attach_encoder(intel_connector, intel_encoder); intel_encoder->type = INTEL_OUTPUT_TVOUT; intel_encoder->crtc_mask = (1 << 0) | (1 << 1); intel_encoder->clone_mask = (1 << INTEL_TV_CLONE_BIT); -- cgit v1.1 From 5ba2aaaaa1a282a71c27f385a743f0d86f3484ca Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Thu, 19 Aug 2010 18:04:08 +0100 Subject: drm/i915/debug: Include Ironlake in self-refresh status Signed-off-by: Chris Wilson --- drivers/gpu/drm/i915/i915_debugfs.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_debugfs.c b/drivers/gpu/drm/i915/i915_debugfs.c index 7700ccf..3d882b7 100644 --- a/drivers/gpu/drm/i915/i915_debugfs.c +++ b/drivers/gpu/drm/i915/i915_debugfs.c @@ -752,15 +752,17 @@ static int i915_sr_status(struct seq_file *m, void *unused) drm_i915_private_t *dev_priv = dev->dev_private; bool sr_enabled = false; - if (IS_I965GM(dev) || IS_I945G(dev) || IS_I945GM(dev)) + if (IS_IRONLAKE(dev)) + sr_enabled = I915_READ(WM1_LP_ILK) & WM1_LP_SR_EN; + else if (IS_I965GM(dev) || IS_I945G(dev) || IS_I945GM(dev)) sr_enabled = I915_READ(FW_BLC_SELF) & FW_BLC_SELF_EN; else if (IS_I915GM(dev)) sr_enabled = I915_READ(INSTPM) & INSTPM_SELF_EN; else if (IS_PINEVIEW(dev)) sr_enabled = I915_READ(DSPFW3) & PINEVIEW_SELF_REFRESH_EN; - seq_printf(m, "self-refresh: %s\n", sr_enabled ? "enabled" : - "disabled"); + seq_printf(m, "self-refresh: %s\n", + sr_enabled ? "enabled" : "disabled"); return 0; } -- cgit v1.1 From e642abbf303741b245375b2e3f8f00e900d462dc Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Thu, 9 Sep 2010 12:46:34 +0100 Subject: drm/i915: Adapt workqueue to new alloc_workqueue interface create_singlethreaded_workqueue() is being phased out for a new concurrency managed task infrastructure. Adapt our workqueue constructor to explicitly create a domain that only allows the execution of a single task at any time. All the tasks are expected to require the dev->struct_mutex, so would block concurrency of other tasks if we allow more than a single i915 task to be run at once. Signed-off-by: Chris Wilson --- drivers/gpu/drm/i915/i915_dma.c | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/i915_dma.c b/drivers/gpu/drm/i915/i915_dma.c index 428c75b..7c7d1bc 100644 --- a/drivers/gpu/drm/i915/i915_dma.c +++ b/drivers/gpu/drm/i915/i915_dma.c @@ -1951,7 +1951,22 @@ int i915_driver_load(struct drm_device *dev, unsigned long flags) prealloc_size = dev_priv->mm.gtt->gtt_stolen_entries << PAGE_SHIFT; agp_size = dev_priv->mm.gtt->gtt_mappable_entries << PAGE_SHIFT; - dev_priv->wq = create_singlethread_workqueue("i915"); + /* The i915 workqueue is primarily used for batched retirement of + * requests (and thus managing bo) once the task has been completed + * by the GPU. i915_gem_retire_requests() is called directly when we + * need high-priority retirement, such as waiting for an explicit + * bo. + * + * It is also used for periodic low-priority events, such as + * idle-timers and hangcheck. + * + * All tasks on the workqueue are expected to acquire the dev mutex + * so there is no point in running more than one instance of the + * workqueue at any time: max_active = 1 and NON_REENTRANT. + */ + dev_priv->wq = alloc_workqueue("i915", + WQ_UNBOUND | WQ_NON_REENTRANT, + 1); if (dev_priv->wq == NULL) { DRM_ERROR("Failed to create our workqueue.\n"); ret = -ENOMEM; -- cgit v1.1 From 6be4a6078e41a8ec511dad35d1377bc5338f97be Mon Sep 17 00:00:00 2001 From: Jesse Barnes Date: Fri, 10 Sep 2010 10:26:01 -0700 Subject: drm/i915: split Ironlake CRTC enable/disable code This way we can also use it in CRTC prepare/commit. Also makes it easier to split out FDI and other code. Signed-off-by: Jesse Barnes Signed-off-by: Chris Wilson --- drivers/gpu/drm/i915/intel_display.c | 591 ++++++++++++++++++----------------- 1 file changed, 310 insertions(+), 281 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index a9df278..56ca589 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -1848,7 +1848,7 @@ static void gen6_fdi_link_train(struct drm_crtc *crtc) DRM_DEBUG_KMS("FDI train done.\n"); } -static void ironlake_crtc_dpms(struct drm_crtc *crtc, int mode) +static void ironlake_crtc_enable(struct drm_crtc *crtc) { struct drm_device *dev = crtc->dev; struct drm_i915_private *dev_priv = dev->dev_private; @@ -1881,339 +1881,368 @@ static void ironlake_crtc_dpms(struct drm_crtc *crtc, int mode) temp = I915_READ(pipeconf_reg); pipe_bpc = temp & PIPE_BPC_MASK; - /* XXX: When our outputs are all unaware of DPMS modes other than off - * and on, we should map those modes to DRM_MODE_DPMS_OFF in the CRTC. - */ - switch (mode) { - case DRM_MODE_DPMS_ON: - case DRM_MODE_DPMS_STANDBY: - case DRM_MODE_DPMS_SUSPEND: - DRM_DEBUG_KMS("crtc %d/%d dpms on\n", pipe, plane); - - if (intel_pipe_has_type(crtc, INTEL_OUTPUT_LVDS)) { - temp = I915_READ(PCH_LVDS); - if ((temp & LVDS_PORT_EN) == 0) { - I915_WRITE(PCH_LVDS, temp | LVDS_PORT_EN); - POSTING_READ(PCH_LVDS); - } + if (intel_pipe_has_type(crtc, INTEL_OUTPUT_LVDS)) { + temp = I915_READ(PCH_LVDS); + if ((temp & LVDS_PORT_EN) == 0) { + I915_WRITE(PCH_LVDS, temp | LVDS_PORT_EN); + POSTING_READ(PCH_LVDS); } + } - if (!HAS_eDP) { - - /* enable PCH FDI RX PLL, wait warmup plus DMI latency */ - temp = I915_READ(fdi_rx_reg); - /* - * make the BPC in FDI Rx be consistent with that in - * pipeconf reg. - */ - temp &= ~(0x7 << 16); - temp |= (pipe_bpc << 11); - temp &= ~(7 << 19); - temp |= (intel_crtc->fdi_lanes - 1) << 19; - I915_WRITE(fdi_rx_reg, temp | FDI_RX_PLL_ENABLE); - I915_READ(fdi_rx_reg); - udelay(200); + if (!HAS_eDP) { + /* enable PCH FDI RX PLL, wait warmup plus DMI latency */ + temp = I915_READ(fdi_rx_reg); + /* + * make the BPC in FDI Rx be consistent with that in + * pipeconf reg. + */ + temp &= ~(0x7 << 16); + temp |= (pipe_bpc << 11); + temp &= ~(7 << 19); + temp |= (intel_crtc->fdi_lanes - 1) << 19; + I915_WRITE(fdi_rx_reg, temp | FDI_RX_PLL_ENABLE); + I915_READ(fdi_rx_reg); + udelay(200); - /* Switch from Rawclk to PCDclk */ - temp = I915_READ(fdi_rx_reg); - I915_WRITE(fdi_rx_reg, temp | FDI_SEL_PCDCLK); - I915_READ(fdi_rx_reg); - udelay(200); + /* Switch from Rawclk to PCDclk */ + temp = I915_READ(fdi_rx_reg); + I915_WRITE(fdi_rx_reg, temp | FDI_SEL_PCDCLK); + I915_READ(fdi_rx_reg); + udelay(200); - /* Enable CPU FDI TX PLL, always on for Ironlake */ - temp = I915_READ(fdi_tx_reg); - if ((temp & FDI_TX_PLL_ENABLE) == 0) { - I915_WRITE(fdi_tx_reg, temp | FDI_TX_PLL_ENABLE); - I915_READ(fdi_tx_reg); - udelay(100); - } + /* Enable CPU FDI TX PLL, always on for Ironlake */ + temp = I915_READ(fdi_tx_reg); + if ((temp & FDI_TX_PLL_ENABLE) == 0) { + I915_WRITE(fdi_tx_reg, temp | FDI_TX_PLL_ENABLE); + I915_READ(fdi_tx_reg); + udelay(100); } + } - /* Enable panel fitting for LVDS */ - if (dev_priv->pch_pf_size && - (intel_pipe_has_type(crtc, INTEL_OUTPUT_LVDS) - || HAS_eDP || intel_pch_has_edp(crtc))) { - /* Force use of hard-coded filter coefficients - * as some pre-programmed values are broken, - * e.g. x201. - */ - I915_WRITE(pipe ? PFB_CTL_1 : PFA_CTL_1, - PF_ENABLE | PF_FILTER_MED_3x3); - I915_WRITE(pipe ? PFB_WIN_POS : PFA_WIN_POS, - dev_priv->pch_pf_pos); - I915_WRITE(pipe ? PFB_WIN_SZ : PFA_WIN_SZ, - dev_priv->pch_pf_size); - } + /* Enable panel fitting for LVDS */ + if (dev_priv->pch_pf_size && + (intel_pipe_has_type(crtc, INTEL_OUTPUT_LVDS) + || HAS_eDP || intel_pch_has_edp(crtc))) { + /* Force use of hard-coded filter coefficients + * as some pre-programmed values are broken, + * e.g. x201. + */ + I915_WRITE(pipe ? PFB_CTL_1 : PFA_CTL_1, + PF_ENABLE | PF_FILTER_MED_3x3); + I915_WRITE(pipe ? PFB_WIN_POS : PFA_WIN_POS, + dev_priv->pch_pf_pos); + I915_WRITE(pipe ? PFB_WIN_SZ : PFA_WIN_SZ, + dev_priv->pch_pf_size); + } - /* Enable CPU pipe */ - temp = I915_READ(pipeconf_reg); - if ((temp & PIPEACONF_ENABLE) == 0) { - I915_WRITE(pipeconf_reg, temp | PIPEACONF_ENABLE); - I915_READ(pipeconf_reg); - udelay(100); - } + /* Enable CPU pipe */ + temp = I915_READ(pipeconf_reg); + if ((temp & PIPEACONF_ENABLE) == 0) { + I915_WRITE(pipeconf_reg, temp | PIPEACONF_ENABLE); + I915_READ(pipeconf_reg); + udelay(100); + } - /* configure and enable CPU plane */ - temp = I915_READ(dspcntr_reg); - if ((temp & DISPLAY_PLANE_ENABLE) == 0) { - I915_WRITE(dspcntr_reg, temp | DISPLAY_PLANE_ENABLE); - /* Flush the plane changes */ - I915_WRITE(dspbase_reg, I915_READ(dspbase_reg)); - } + /* configure and enable CPU plane */ + temp = I915_READ(dspcntr_reg); + if ((temp & DISPLAY_PLANE_ENABLE) == 0) { + I915_WRITE(dspcntr_reg, temp | DISPLAY_PLANE_ENABLE); + /* Flush the plane changes */ + I915_WRITE(dspbase_reg, I915_READ(dspbase_reg)); + } - if (!HAS_eDP) { - /* For PCH output, training FDI link */ - if (IS_GEN6(dev)) - gen6_fdi_link_train(crtc); - else - ironlake_fdi_link_train(crtc); + if (!HAS_eDP) { + /* For PCH output, training FDI link */ + if (IS_GEN6(dev)) + gen6_fdi_link_train(crtc); + else + ironlake_fdi_link_train(crtc); - /* enable PCH DPLL */ - temp = I915_READ(pch_dpll_reg); - if ((temp & DPLL_VCO_ENABLE) == 0) { - I915_WRITE(pch_dpll_reg, temp | DPLL_VCO_ENABLE); - I915_READ(pch_dpll_reg); - } - udelay(200); + /* enable PCH DPLL */ + temp = I915_READ(pch_dpll_reg); + if ((temp & DPLL_VCO_ENABLE) == 0) { + I915_WRITE(pch_dpll_reg, temp | DPLL_VCO_ENABLE); + I915_READ(pch_dpll_reg); + } + udelay(200); - if (HAS_PCH_CPT(dev)) { - /* Be sure PCH DPLL SEL is set */ - temp = I915_READ(PCH_DPLL_SEL); - if (trans_dpll_sel == 0 && - (temp & TRANSA_DPLL_ENABLE) == 0) - temp |= (TRANSA_DPLL_ENABLE | TRANSA_DPLLA_SEL); - else if (trans_dpll_sel == 1 && - (temp & TRANSB_DPLL_ENABLE) == 0) - temp |= (TRANSB_DPLL_ENABLE | TRANSB_DPLLB_SEL); - I915_WRITE(PCH_DPLL_SEL, temp); - I915_READ(PCH_DPLL_SEL); - } + if (HAS_PCH_CPT(dev)) { + /* Be sure PCH DPLL SEL is set */ + temp = I915_READ(PCH_DPLL_SEL); + if (trans_dpll_sel == 0 && + (temp & TRANSA_DPLL_ENABLE) == 0) + temp |= (TRANSA_DPLL_ENABLE | TRANSA_DPLLA_SEL); + else if (trans_dpll_sel == 1 && + (temp & TRANSB_DPLL_ENABLE) == 0) + temp |= (TRANSB_DPLL_ENABLE | TRANSB_DPLLB_SEL); + I915_WRITE(PCH_DPLL_SEL, temp); + I915_READ(PCH_DPLL_SEL); + } + /* set transcoder timing */ + I915_WRITE(trans_htot_reg, I915_READ(cpu_htot_reg)); + I915_WRITE(trans_hblank_reg, I915_READ(cpu_hblank_reg)); + I915_WRITE(trans_hsync_reg, I915_READ(cpu_hsync_reg)); - /* set transcoder timing */ - I915_WRITE(trans_htot_reg, I915_READ(cpu_htot_reg)); - I915_WRITE(trans_hblank_reg, I915_READ(cpu_hblank_reg)); - I915_WRITE(trans_hsync_reg, I915_READ(cpu_hsync_reg)); + I915_WRITE(trans_vtot_reg, I915_READ(cpu_vtot_reg)); + I915_WRITE(trans_vblank_reg, I915_READ(cpu_vblank_reg)); + I915_WRITE(trans_vsync_reg, I915_READ(cpu_vsync_reg)); - I915_WRITE(trans_vtot_reg, I915_READ(cpu_vtot_reg)); - I915_WRITE(trans_vblank_reg, I915_READ(cpu_vblank_reg)); - I915_WRITE(trans_vsync_reg, I915_READ(cpu_vsync_reg)); + /* enable normal train */ + temp = I915_READ(fdi_tx_reg); + temp &= ~FDI_LINK_TRAIN_NONE; + I915_WRITE(fdi_tx_reg, temp | FDI_LINK_TRAIN_NONE | + FDI_TX_ENHANCE_FRAME_ENABLE); + I915_READ(fdi_tx_reg); - /* enable normal train */ - temp = I915_READ(fdi_tx_reg); + temp = I915_READ(fdi_rx_reg); + if (HAS_PCH_CPT(dev)) { + temp &= ~FDI_LINK_TRAIN_PATTERN_MASK_CPT; + temp |= FDI_LINK_TRAIN_NORMAL_CPT; + } else { temp &= ~FDI_LINK_TRAIN_NONE; - I915_WRITE(fdi_tx_reg, temp | FDI_LINK_TRAIN_NONE | - FDI_TX_ENHANCE_FRAME_ENABLE); - I915_READ(fdi_tx_reg); + temp |= FDI_LINK_TRAIN_NONE; + } + I915_WRITE(fdi_rx_reg, temp | FDI_RX_ENHANCE_FRAME_ENABLE); + I915_READ(fdi_rx_reg); - temp = I915_READ(fdi_rx_reg); - if (HAS_PCH_CPT(dev)) { - temp &= ~FDI_LINK_TRAIN_PATTERN_MASK_CPT; - temp |= FDI_LINK_TRAIN_NORMAL_CPT; - } else { - temp &= ~FDI_LINK_TRAIN_NONE; - temp |= FDI_LINK_TRAIN_NONE; + /* wait one idle pattern time */ + udelay(100); + + /* For PCH DP, enable TRANS_DP_CTL */ + if (HAS_PCH_CPT(dev) && + intel_pipe_has_type(crtc, INTEL_OUTPUT_DISPLAYPORT)) { + int trans_dp_ctl = (pipe == 0) ? TRANS_DP_CTL_A : TRANS_DP_CTL_B; + int reg; + + reg = I915_READ(trans_dp_ctl); + reg &= ~(TRANS_DP_PORT_SEL_MASK | + TRANS_DP_SYNC_MASK); + reg |= (TRANS_DP_OUTPUT_ENABLE | + TRANS_DP_ENH_FRAMING); + + if (crtc->mode.flags & DRM_MODE_FLAG_PHSYNC) + reg |= TRANS_DP_HSYNC_ACTIVE_HIGH; + if (crtc->mode.flags & DRM_MODE_FLAG_PVSYNC) + reg |= TRANS_DP_VSYNC_ACTIVE_HIGH; + + switch (intel_trans_dp_port_sel(crtc)) { + case PCH_DP_B: + reg |= TRANS_DP_PORT_SEL_B; + break; + case PCH_DP_C: + reg |= TRANS_DP_PORT_SEL_C; + break; + case PCH_DP_D: + reg |= TRANS_DP_PORT_SEL_D; + break; + default: + DRM_DEBUG_KMS("Wrong PCH DP port return. Guess port B\n"); + reg |= TRANS_DP_PORT_SEL_B; + break; } - I915_WRITE(fdi_rx_reg, temp | FDI_RX_ENHANCE_FRAME_ENABLE); - I915_READ(fdi_rx_reg); - /* wait one idle pattern time */ - udelay(100); + I915_WRITE(trans_dp_ctl, reg); + POSTING_READ(trans_dp_ctl); + } - /* For PCH DP, enable TRANS_DP_CTL */ - if (HAS_PCH_CPT(dev) && - intel_pipe_has_type(crtc, INTEL_OUTPUT_DISPLAYPORT)) { - int trans_dp_ctl = (pipe == 0) ? TRANS_DP_CTL_A : TRANS_DP_CTL_B; - int reg; - - reg = I915_READ(trans_dp_ctl); - reg &= ~(TRANS_DP_PORT_SEL_MASK | - TRANS_DP_SYNC_MASK); - reg |= (TRANS_DP_OUTPUT_ENABLE | - TRANS_DP_ENH_FRAMING); - - if (crtc->mode.flags & DRM_MODE_FLAG_PHSYNC) - reg |= TRANS_DP_HSYNC_ACTIVE_HIGH; - if (crtc->mode.flags & DRM_MODE_FLAG_PVSYNC) - reg |= TRANS_DP_VSYNC_ACTIVE_HIGH; - - switch (intel_trans_dp_port_sel(crtc)) { - case PCH_DP_B: - reg |= TRANS_DP_PORT_SEL_B; - break; - case PCH_DP_C: - reg |= TRANS_DP_PORT_SEL_C; - break; - case PCH_DP_D: - reg |= TRANS_DP_PORT_SEL_D; - break; - default: - DRM_DEBUG_KMS("Wrong PCH DP port return. Guess port B\n"); - reg |= TRANS_DP_PORT_SEL_B; - break; - } + /* enable PCH transcoder */ + temp = I915_READ(transconf_reg); + /* + * make the BPC in transcoder be consistent with + * that in pipeconf reg. + */ + temp &= ~PIPE_BPC_MASK; + temp |= pipe_bpc; + I915_WRITE(transconf_reg, temp | TRANS_ENABLE); + I915_READ(transconf_reg); - I915_WRITE(trans_dp_ctl, reg); - POSTING_READ(trans_dp_ctl); - } + if (wait_for(I915_READ(transconf_reg) & TRANS_STATE_ENABLE, 100)) + DRM_ERROR("failed to enable transcoder\n"); + } - /* enable PCH transcoder */ - temp = I915_READ(transconf_reg); - /* - * make the BPC in transcoder be consistent with - * that in pipeconf reg. - */ - temp &= ~PIPE_BPC_MASK; - temp |= pipe_bpc; - I915_WRITE(transconf_reg, temp | TRANS_ENABLE); - I915_READ(transconf_reg); + intel_crtc_load_lut(crtc); - if (wait_for(I915_READ(transconf_reg) & TRANS_STATE_ENABLE, 100)) - DRM_ERROR("failed to enable transcoder\n"); - } + intel_update_fbc(crtc, &crtc->mode); +} - intel_crtc_load_lut(crtc); +static void ironlake_crtc_disable(struct drm_crtc *crtc) +{ + struct drm_device *dev = crtc->dev; + struct drm_i915_private *dev_priv = dev->dev_private; + struct intel_crtc *intel_crtc = to_intel_crtc(crtc); + int pipe = intel_crtc->pipe; + int plane = intel_crtc->plane; + int pch_dpll_reg = (pipe == 0) ? PCH_DPLL_A : PCH_DPLL_B; + int pipeconf_reg = (pipe == 0) ? PIPEACONF : PIPEBCONF; + int dspcntr_reg = (plane == 0) ? DSPACNTR : DSPBCNTR; + int dspbase_reg = (plane == 0) ? DSPAADDR : DSPBADDR; + int fdi_tx_reg = (pipe == 0) ? FDI_TXA_CTL : FDI_TXB_CTL; + int fdi_rx_reg = (pipe == 0) ? FDI_RXA_CTL : FDI_RXB_CTL; + int transconf_reg = (pipe == 0) ? TRANSACONF : TRANSBCONF; + int trans_dpll_sel = (pipe == 0) ? 0 : 1; + u32 temp; + u32 pipe_bpc; - intel_update_fbc(crtc, &crtc->mode); - break; + temp = I915_READ(pipeconf_reg); + pipe_bpc = temp & PIPE_BPC_MASK; - case DRM_MODE_DPMS_OFF: - DRM_DEBUG_KMS("crtc %d/%d dpms off\n", pipe, plane); + drm_vblank_off(dev, pipe); + /* Disable display plane */ + temp = I915_READ(dspcntr_reg); + if ((temp & DISPLAY_PLANE_ENABLE) != 0) { + I915_WRITE(dspcntr_reg, temp & ~DISPLAY_PLANE_ENABLE); + /* Flush the plane changes */ + I915_WRITE(dspbase_reg, I915_READ(dspbase_reg)); + I915_READ(dspbase_reg); + } - drm_vblank_off(dev, pipe); - /* Disable display plane */ - temp = I915_READ(dspcntr_reg); - if ((temp & DISPLAY_PLANE_ENABLE) != 0) { - I915_WRITE(dspcntr_reg, temp & ~DISPLAY_PLANE_ENABLE); - /* Flush the plane changes */ - I915_WRITE(dspbase_reg, I915_READ(dspbase_reg)); - I915_READ(dspbase_reg); - } + if (dev_priv->cfb_plane == plane && + dev_priv->display.disable_fbc) + dev_priv->display.disable_fbc(dev); - if (dev_priv->cfb_plane == plane && - dev_priv->display.disable_fbc) - dev_priv->display.disable_fbc(dev); + /* disable cpu pipe, disable after all planes disabled */ + temp = I915_READ(pipeconf_reg); + if ((temp & PIPEACONF_ENABLE) != 0) { + I915_WRITE(pipeconf_reg, temp & ~PIPEACONF_ENABLE); - /* disable cpu pipe, disable after all planes disabled */ - temp = I915_READ(pipeconf_reg); - if ((temp & PIPEACONF_ENABLE) != 0) { - I915_WRITE(pipeconf_reg, temp & ~PIPEACONF_ENABLE); + /* wait for cpu pipe off, pipe state */ + if (wait_for((I915_READ(pipeconf_reg) & I965_PIPECONF_ACTIVE) == 0, 50)) + DRM_ERROR("failed to turn off cpu pipe\n"); + } else + DRM_DEBUG_KMS("crtc %d is disabled\n", pipe); - /* wait for cpu pipe off, pipe state */ - if (wait_for((I915_READ(pipeconf_reg) & I965_PIPECONF_ACTIVE) == 0, 50)) - DRM_ERROR("failed to turn off cpu pipe\n"); - } else - DRM_DEBUG_KMS("crtc %d is disabled\n", pipe); + udelay(100); - udelay(100); + /* Disable PF */ + I915_WRITE(pipe ? PFB_CTL_1 : PFA_CTL_1, 0); + I915_WRITE(pipe ? PFB_WIN_SZ : PFA_WIN_SZ, 0); - /* Disable PF */ - I915_WRITE(pipe ? PFB_CTL_1 : PFA_CTL_1, 0); - I915_WRITE(pipe ? PFB_WIN_SZ : PFA_WIN_SZ, 0); + /* disable CPU FDI tx and PCH FDI rx */ + temp = I915_READ(fdi_tx_reg); + I915_WRITE(fdi_tx_reg, temp & ~FDI_TX_ENABLE); + I915_READ(fdi_tx_reg); - /* disable CPU FDI tx and PCH FDI rx */ - temp = I915_READ(fdi_tx_reg); - I915_WRITE(fdi_tx_reg, temp & ~FDI_TX_ENABLE); - I915_READ(fdi_tx_reg); + temp = I915_READ(fdi_rx_reg); + /* BPC in FDI rx is consistent with that in pipeconf */ + temp &= ~(0x07 << 16); + temp |= (pipe_bpc << 11); + I915_WRITE(fdi_rx_reg, temp & ~FDI_RX_ENABLE); + I915_READ(fdi_rx_reg); - temp = I915_READ(fdi_rx_reg); - /* BPC in FDI rx is consistent with that in pipeconf */ - temp &= ~(0x07 << 16); - temp |= (pipe_bpc << 11); - I915_WRITE(fdi_rx_reg, temp & ~FDI_RX_ENABLE); - I915_READ(fdi_rx_reg); + udelay(100); - udelay(100); + /* still set train pattern 1 */ + temp = I915_READ(fdi_tx_reg); + temp &= ~FDI_LINK_TRAIN_NONE; + temp |= FDI_LINK_TRAIN_PATTERN_1; + I915_WRITE(fdi_tx_reg, temp); + POSTING_READ(fdi_tx_reg); - /* still set train pattern 1 */ - temp = I915_READ(fdi_tx_reg); + temp = I915_READ(fdi_rx_reg); + if (HAS_PCH_CPT(dev)) { + temp &= ~FDI_LINK_TRAIN_PATTERN_MASK_CPT; + temp |= FDI_LINK_TRAIN_PATTERN_1_CPT; + } else { temp &= ~FDI_LINK_TRAIN_NONE; temp |= FDI_LINK_TRAIN_PATTERN_1; - I915_WRITE(fdi_tx_reg, temp); - POSTING_READ(fdi_tx_reg); + } + I915_WRITE(fdi_rx_reg, temp); + POSTING_READ(fdi_rx_reg); - temp = I915_READ(fdi_rx_reg); - if (HAS_PCH_CPT(dev)) { - temp &= ~FDI_LINK_TRAIN_PATTERN_MASK_CPT; - temp |= FDI_LINK_TRAIN_PATTERN_1_CPT; - } else { - temp &= ~FDI_LINK_TRAIN_NONE; - temp |= FDI_LINK_TRAIN_PATTERN_1; - } - I915_WRITE(fdi_rx_reg, temp); - POSTING_READ(fdi_rx_reg); + udelay(100); + if (intel_pipe_has_type(crtc, INTEL_OUTPUT_LVDS)) { + temp = I915_READ(PCH_LVDS); + I915_WRITE(PCH_LVDS, temp & ~LVDS_PORT_EN); + I915_READ(PCH_LVDS); udelay(100); + } - if (intel_pipe_has_type(crtc, INTEL_OUTPUT_LVDS)) { - temp = I915_READ(PCH_LVDS); - I915_WRITE(PCH_LVDS, temp & ~LVDS_PORT_EN); - I915_READ(PCH_LVDS); - udelay(100); - } + /* disable PCH transcoder */ + temp = I915_READ(transconf_reg); + if ((temp & TRANS_ENABLE) != 0) { + I915_WRITE(transconf_reg, temp & ~TRANS_ENABLE); - /* disable PCH transcoder */ - temp = I915_READ(transconf_reg); - if ((temp & TRANS_ENABLE) != 0) { - I915_WRITE(transconf_reg, temp & ~TRANS_ENABLE); + /* wait for PCH transcoder off, transcoder state */ + if (wait_for((I915_READ(transconf_reg) & TRANS_STATE_ENABLE) == 0, 50)) + DRM_ERROR("failed to disable transcoder\n"); + } - /* wait for PCH transcoder off, transcoder state */ - if (wait_for((I915_READ(transconf_reg) & TRANS_STATE_ENABLE) == 0, 50)) - DRM_ERROR("failed to disable transcoder\n"); - } + temp = I915_READ(transconf_reg); + /* BPC in transcoder is consistent with that in pipeconf */ + temp &= ~PIPE_BPC_MASK; + temp |= pipe_bpc; + I915_WRITE(transconf_reg, temp); + I915_READ(transconf_reg); + udelay(100); - temp = I915_READ(transconf_reg); - /* BPC in transcoder is consistent with that in pipeconf */ - temp &= ~PIPE_BPC_MASK; - temp |= pipe_bpc; - I915_WRITE(transconf_reg, temp); - I915_READ(transconf_reg); - udelay(100); + if (HAS_PCH_CPT(dev)) { + /* disable TRANS_DP_CTL */ + int trans_dp_ctl = (pipe == 0) ? TRANS_DP_CTL_A : TRANS_DP_CTL_B; + int reg; - if (HAS_PCH_CPT(dev)) { - /* disable TRANS_DP_CTL */ - int trans_dp_ctl = (pipe == 0) ? TRANS_DP_CTL_A : TRANS_DP_CTL_B; - int reg; + reg = I915_READ(trans_dp_ctl); + reg &= ~(TRANS_DP_OUTPUT_ENABLE | TRANS_DP_PORT_SEL_MASK); + I915_WRITE(trans_dp_ctl, reg); + POSTING_READ(trans_dp_ctl); - reg = I915_READ(trans_dp_ctl); - reg &= ~(TRANS_DP_OUTPUT_ENABLE | TRANS_DP_PORT_SEL_MASK); - I915_WRITE(trans_dp_ctl, reg); - POSTING_READ(trans_dp_ctl); + /* disable DPLL_SEL */ + temp = I915_READ(PCH_DPLL_SEL); + if (trans_dpll_sel == 0) + temp &= ~(TRANSA_DPLL_ENABLE | TRANSA_DPLLB_SEL); + else + temp &= ~(TRANSB_DPLL_ENABLE | TRANSB_DPLLB_SEL); + I915_WRITE(PCH_DPLL_SEL, temp); + I915_READ(PCH_DPLL_SEL); - /* disable DPLL_SEL */ - temp = I915_READ(PCH_DPLL_SEL); - if (trans_dpll_sel == 0) - temp &= ~(TRANSA_DPLL_ENABLE | TRANSA_DPLLB_SEL); - else - temp &= ~(TRANSB_DPLL_ENABLE | TRANSB_DPLLB_SEL); - I915_WRITE(PCH_DPLL_SEL, temp); - I915_READ(PCH_DPLL_SEL); + } - } + /* disable PCH DPLL */ + temp = I915_READ(pch_dpll_reg); + I915_WRITE(pch_dpll_reg, temp & ~DPLL_VCO_ENABLE); + I915_READ(pch_dpll_reg); - /* disable PCH DPLL */ - temp = I915_READ(pch_dpll_reg); - I915_WRITE(pch_dpll_reg, temp & ~DPLL_VCO_ENABLE); - I915_READ(pch_dpll_reg); + /* Switch from PCDclk to Rawclk */ + temp = I915_READ(fdi_rx_reg); + temp &= ~FDI_SEL_PCDCLK; + I915_WRITE(fdi_rx_reg, temp); + I915_READ(fdi_rx_reg); - /* Switch from PCDclk to Rawclk */ - temp = I915_READ(fdi_rx_reg); - temp &= ~FDI_SEL_PCDCLK; - I915_WRITE(fdi_rx_reg, temp); - I915_READ(fdi_rx_reg); + /* Disable CPU FDI TX PLL */ + temp = I915_READ(fdi_tx_reg); + I915_WRITE(fdi_tx_reg, temp & ~FDI_TX_PLL_ENABLE); + I915_READ(fdi_tx_reg); + udelay(100); - /* Disable CPU FDI TX PLL */ - temp = I915_READ(fdi_tx_reg); - I915_WRITE(fdi_tx_reg, temp & ~FDI_TX_PLL_ENABLE); - I915_READ(fdi_tx_reg); - udelay(100); + temp = I915_READ(fdi_rx_reg); + temp &= ~FDI_RX_PLL_ENABLE; + I915_WRITE(fdi_rx_reg, temp); + I915_READ(fdi_rx_reg); - temp = I915_READ(fdi_rx_reg); - temp &= ~FDI_RX_PLL_ENABLE; - I915_WRITE(fdi_rx_reg, temp); - I915_READ(fdi_rx_reg); + /* Wait for the clocks to turn off. */ + udelay(100); +} - /* Wait for the clocks to turn off. */ - udelay(100); +static void ironlake_crtc_dpms(struct drm_crtc *crtc, int mode) +{ + struct intel_crtc *intel_crtc = to_intel_crtc(crtc); + int pipe = intel_crtc->pipe; + int plane = intel_crtc->plane; + + /* XXX: When our outputs are all unaware of DPMS modes other than off + * and on, we should map those modes to DRM_MODE_DPMS_OFF in the CRTC. + */ + switch (mode) { + case DRM_MODE_DPMS_ON: + case DRM_MODE_DPMS_STANDBY: + case DRM_MODE_DPMS_SUSPEND: + DRM_DEBUG_KMS("crtc %d/%d dpms on\n", pipe, plane); + ironlake_crtc_enable(crtc); + break; + + case DRM_MODE_DPMS_OFF: + DRM_DEBUG_KMS("crtc %d/%d dpms off\n", pipe, plane); + ironlake_crtc_disable(crtc); break; } } -- cgit v1.1 From 0b8765c6e7fb6e0aaa9b9081454fb0f202852523 Mon Sep 17 00:00:00 2001 From: Jesse Barnes Date: Fri, 10 Sep 2010 10:31:34 -0700 Subject: drm/i915: split i9xx CRTC enable/disable code So we can use it for CRTC prepare/commit. Signed-off-by: Jesse Barnes Signed-off-by: Chris Wilson --- drivers/gpu/drm/i915/intel_display.c | 185 +++++++++++++++++++---------------- 1 file changed, 103 insertions(+), 82 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 56ca589..fecb98c 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -2262,7 +2262,7 @@ static void intel_crtc_dpms_overlay(struct intel_crtc *intel_crtc, bool enable) */ } -static void i9xx_crtc_dpms(struct drm_crtc *crtc, int mode) +static void i9xx_crtc_enable(struct drm_crtc *crtc) { struct drm_device *dev = crtc->dev; struct drm_i915_private *dev_priv = dev->dev_private; @@ -2275,97 +2275,118 @@ static void i9xx_crtc_dpms(struct drm_crtc *crtc, int mode) int pipeconf_reg = (pipe == 0) ? PIPEACONF : PIPEBCONF; u32 temp; - /* XXX: When our outputs are all unaware of DPMS modes other than off - * and on, we should map those modes to DRM_MODE_DPMS_OFF in the CRTC. - */ - switch (mode) { - case DRM_MODE_DPMS_ON: - case DRM_MODE_DPMS_STANDBY: - case DRM_MODE_DPMS_SUSPEND: - /* Enable the DPLL */ - temp = I915_READ(dpll_reg); - if ((temp & DPLL_VCO_ENABLE) == 0) { - I915_WRITE(dpll_reg, temp); - I915_READ(dpll_reg); - /* Wait for the clocks to stabilize. */ - udelay(150); - I915_WRITE(dpll_reg, temp | DPLL_VCO_ENABLE); - I915_READ(dpll_reg); - /* Wait for the clocks to stabilize. */ - udelay(150); - I915_WRITE(dpll_reg, temp | DPLL_VCO_ENABLE); - I915_READ(dpll_reg); - /* Wait for the clocks to stabilize. */ - udelay(150); - } + /* Enable the DPLL */ + temp = I915_READ(dpll_reg); + if ((temp & DPLL_VCO_ENABLE) == 0) { + I915_WRITE(dpll_reg, temp); + I915_READ(dpll_reg); + /* Wait for the clocks to stabilize. */ + udelay(150); + I915_WRITE(dpll_reg, temp | DPLL_VCO_ENABLE); + I915_READ(dpll_reg); + /* Wait for the clocks to stabilize. */ + udelay(150); + I915_WRITE(dpll_reg, temp | DPLL_VCO_ENABLE); + I915_READ(dpll_reg); + /* Wait for the clocks to stabilize. */ + udelay(150); + } - /* Enable the pipe */ - temp = I915_READ(pipeconf_reg); - if ((temp & PIPEACONF_ENABLE) == 0) - I915_WRITE(pipeconf_reg, temp | PIPEACONF_ENABLE); - - /* Enable the plane */ - temp = I915_READ(dspcntr_reg); - if ((temp & DISPLAY_PLANE_ENABLE) == 0) { - I915_WRITE(dspcntr_reg, temp | DISPLAY_PLANE_ENABLE); - /* Flush the plane changes */ - I915_WRITE(dspbase_reg, I915_READ(dspbase_reg)); - } + /* Enable the pipe */ + temp = I915_READ(pipeconf_reg); + if ((temp & PIPEACONF_ENABLE) == 0) + I915_WRITE(pipeconf_reg, temp | PIPEACONF_ENABLE); - intel_crtc_load_lut(crtc); + /* Enable the plane */ + temp = I915_READ(dspcntr_reg); + if ((temp & DISPLAY_PLANE_ENABLE) == 0) { + I915_WRITE(dspcntr_reg, temp | DISPLAY_PLANE_ENABLE); + /* Flush the plane changes */ + I915_WRITE(dspbase_reg, I915_READ(dspbase_reg)); + } - if ((IS_I965G(dev) || plane == 0)) - intel_update_fbc(crtc, &crtc->mode); + intel_crtc_load_lut(crtc); - /* Give the overlay scaler a chance to enable if it's on this pipe */ - intel_crtc_dpms_overlay(intel_crtc, true); - break; - case DRM_MODE_DPMS_OFF: - /* Give the overlay scaler a chance to disable if it's on this pipe */ - intel_crtc_dpms_overlay(intel_crtc, false); - drm_vblank_off(dev, pipe); - - if (dev_priv->cfb_plane == plane && - dev_priv->display.disable_fbc) - dev_priv->display.disable_fbc(dev); - - /* Disable display plane */ - temp = I915_READ(dspcntr_reg); - if ((temp & DISPLAY_PLANE_ENABLE) != 0) { - I915_WRITE(dspcntr_reg, temp & ~DISPLAY_PLANE_ENABLE); - /* Flush the plane changes */ - I915_WRITE(dspbase_reg, I915_READ(dspbase_reg)); - I915_READ(dspbase_reg); - } + if ((IS_I965G(dev) || plane == 0)) + intel_update_fbc(crtc, &crtc->mode); - if (!IS_I9XX(dev)) { - /* Wait for vblank for the disable to take effect */ - intel_wait_for_vblank_off(dev, pipe); - } + /* Give the overlay scaler a chance to enable if it's on this pipe */ + intel_crtc_dpms_overlay(intel_crtc, true); +} - /* Don't disable pipe A or pipe A PLLs if needed */ - if (pipeconf_reg == PIPEACONF && - (dev_priv->quirks & QUIRK_PIPEA_FORCE)) - goto skip_pipe_off; +static void i9xx_crtc_disable(struct drm_crtc *crtc) +{ + struct drm_device *dev = crtc->dev; + struct drm_i915_private *dev_priv = dev->dev_private; + struct intel_crtc *intel_crtc = to_intel_crtc(crtc); + int pipe = intel_crtc->pipe; + int plane = intel_crtc->plane; + int dpll_reg = (pipe == 0) ? DPLL_A : DPLL_B; + int dspcntr_reg = (plane == 0) ? DSPACNTR : DSPBCNTR; + int dspbase_reg = (plane == 0) ? DSPAADDR : DSPBADDR; + int pipeconf_reg = (pipe == 0) ? PIPEACONF : PIPEBCONF; + u32 temp; - /* Next, disable display pipes */ - temp = I915_READ(pipeconf_reg); - if ((temp & PIPEACONF_ENABLE) != 0) { - I915_WRITE(pipeconf_reg, temp & ~PIPEACONF_ENABLE); - I915_READ(pipeconf_reg); - } + /* Give the overlay scaler a chance to disable if it's on this pipe */ + intel_crtc_dpms_overlay(intel_crtc, false); + drm_vblank_off(dev, pipe); + + if (dev_priv->cfb_plane == plane && + dev_priv->display.disable_fbc) + dev_priv->display.disable_fbc(dev); - /* Wait for vblank for the disable to take effect. */ + /* Disable display plane */ + temp = I915_READ(dspcntr_reg); + if ((temp & DISPLAY_PLANE_ENABLE) != 0) { + I915_WRITE(dspcntr_reg, temp & ~DISPLAY_PLANE_ENABLE); + /* Flush the plane changes */ + I915_WRITE(dspbase_reg, I915_READ(dspbase_reg)); + I915_READ(dspbase_reg); + } + + if (!IS_I9XX(dev)) { + /* Wait for vblank for the disable to take effect */ intel_wait_for_vblank_off(dev, pipe); + } - temp = I915_READ(dpll_reg); - if ((temp & DPLL_VCO_ENABLE) != 0) { - I915_WRITE(dpll_reg, temp & ~DPLL_VCO_ENABLE); - I915_READ(dpll_reg); - } - skip_pipe_off: - /* Wait for the clocks to turn off. */ - udelay(150); + /* Don't disable pipe A or pipe A PLLs if needed */ + if (pipeconf_reg == PIPEACONF && + (dev_priv->quirks & QUIRK_PIPEA_FORCE)) + goto skip_pipe_off; + + /* Next, disable display pipes */ + temp = I915_READ(pipeconf_reg); + if ((temp & PIPEACONF_ENABLE) != 0) { + I915_WRITE(pipeconf_reg, temp & ~PIPEACONF_ENABLE); + I915_READ(pipeconf_reg); + } + + /* Wait for vblank for the disable to take effect. */ + intel_wait_for_vblank_off(dev, pipe); + + temp = I915_READ(dpll_reg); + if ((temp & DPLL_VCO_ENABLE) != 0) { + I915_WRITE(dpll_reg, temp & ~DPLL_VCO_ENABLE); + I915_READ(dpll_reg); + } +skip_pipe_off: + /* Wait for the clocks to turn off. */ + udelay(150); +} + +static void i9xx_crtc_dpms(struct drm_crtc *crtc, int mode) +{ + /* XXX: When our outputs are all unaware of DPMS modes other than off + * and on, we should map those modes to DRM_MODE_DPMS_OFF in the CRTC. + */ + switch (mode) { + case DRM_MODE_DPMS_ON: + case DRM_MODE_DPMS_STANDBY: + case DRM_MODE_DPMS_SUSPEND: + i9xx_crtc_enable(crtc); + break; + case DRM_MODE_DPMS_OFF: + i9xx_crtc_disable(crtc); break; } } -- cgit v1.1 From 4d12fe0b4864682d3562021cde0f32961c655d75 Mon Sep 17 00:00:00 2001 From: Jesse Barnes Date: Fri, 10 Sep 2010 10:46:45 -0700 Subject: drm/i915: don't unlock panel regs This was just a workaround for some broken Ironlake CRTC code. Signed-off-by: Jesse Barnes Signed-off-by: Chris Wilson --- drivers/gpu/drm/i915/intel_dp.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c index b9efeaf..103a60b 100644 --- a/drivers/gpu/drm/i915/intel_dp.c +++ b/drivers/gpu/drm/i915/intel_dp.c @@ -781,7 +781,7 @@ static bool ironlake_edp_panel_on (struct drm_device *dev) I915_WRITE(PCH_PP_CONTROL, pp); POSTING_READ(PCH_PP_CONTROL); - pp |= PANEL_UNLOCK_REGS | POWER_TARGET_ON; + pp |= POWER_TARGET_ON; I915_WRITE(PCH_PP_CONTROL, pp); if (wait_for(I915_READ(PCH_PP_STATUS) & PP_ON, 5000)) -- cgit v1.1 From 7e7d76c306adb73a41d2678a42a11004df2519b7 Mon Sep 17 00:00:00 2001 From: Jesse Barnes Date: Fri, 10 Sep 2010 10:47:20 -0700 Subject: drm/i915: use i915 and Ironlake CRTC enable/disable functions in prepare/commit This will allow us to optimize our prepare/commit paths a bit better. Signed-off-by: Jesse Barnes [ickle: minor tweak to handle the cursor across pipe resizing] Signed-off-by: Chris Wilson --- drivers/gpu/drm/i915/intel_display.c | 69 +++++++++++++++++++++++++++++++----- 1 file changed, 60 insertions(+), 9 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index fecb98c..98276b8 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -2478,16 +2478,60 @@ static void intel_crtc_dpms(struct drm_crtc *crtc, int mode) } } -static void intel_crtc_prepare (struct drm_crtc *crtc) +/* Prepare for a mode set. + * + * Note we could be a lot smarter here. We need to figure out which outputs + * will be enabled, which disabled (in short, how the config will changes) + * and perform the minimum necessary steps to accomplish that, e.g. updating + * watermarks, FBC configuration, making sure PLLs are programmed correctly, + * panel fitting is in the proper state, etc. + */ +static void i9xx_crtc_prepare(struct drm_crtc *crtc) { - struct drm_crtc_helper_funcs *crtc_funcs = crtc->helper_private; - crtc_funcs->dpms(crtc, DRM_MODE_DPMS_OFF); + struct drm_device *dev = crtc->dev; + struct intel_crtc *intel_crtc = to_intel_crtc(crtc); + + intel_crtc->cursor_on = false; + intel_crtc_update_cursor(crtc); + + i9xx_crtc_disable(crtc); + intel_clear_scanline_wait(dev); } -static void intel_crtc_commit (struct drm_crtc *crtc) +static void i9xx_crtc_commit(struct drm_crtc *crtc) { - struct drm_crtc_helper_funcs *crtc_funcs = crtc->helper_private; - crtc_funcs->dpms(crtc, DRM_MODE_DPMS_ON); + struct drm_device *dev = crtc->dev; + struct intel_crtc *intel_crtc = to_intel_crtc(crtc); + + intel_update_watermarks(dev); + i9xx_crtc_enable(crtc); + + intel_crtc->cursor_on = true; + intel_crtc_update_cursor(crtc); +} + +static void ironlake_crtc_prepare(struct drm_crtc *crtc) +{ + struct drm_device *dev = crtc->dev; + struct intel_crtc *intel_crtc = to_intel_crtc(crtc); + + intel_crtc->cursor_on = false; + intel_crtc_update_cursor(crtc); + + ironlake_crtc_disable(crtc); + intel_clear_scanline_wait(dev); +} + +static void ironlake_crtc_commit(struct drm_crtc *crtc) +{ + struct drm_device *dev = crtc->dev; + struct intel_crtc *intel_crtc = to_intel_crtc(crtc); + + intel_update_watermarks(dev); + ironlake_crtc_enable(crtc); + + intel_crtc->cursor_on = true; + intel_crtc_update_cursor(crtc); } void intel_encoder_prepare (struct drm_encoder *encoder) @@ -5184,14 +5228,12 @@ cleanup_work: return ret; } -static const struct drm_crtc_helper_funcs intel_helper_funcs = { +static struct drm_crtc_helper_funcs intel_helper_funcs = { .dpms = intel_crtc_dpms, .mode_fixup = intel_crtc_mode_fixup, .mode_set = intel_crtc_mode_set, .mode_set_base = intel_pipe_set_base, .mode_set_base_atomic = intel_pipe_set_base_atomic, - .prepare = intel_crtc_prepare, - .commit = intel_crtc_commit, .load_lut = intel_crtc_load_lut, }; @@ -5241,6 +5283,15 @@ static void intel_crtc_init(struct drm_device *dev, int pipe) intel_crtc->cursor_addr = 0; intel_crtc->dpms_mode = -1; + + if (HAS_PCH_SPLIT(dev)) { + intel_helper_funcs.prepare = ironlake_crtc_prepare; + intel_helper_funcs.commit = ironlake_crtc_commit; + } else { + intel_helper_funcs.prepare = i9xx_crtc_prepare; + intel_helper_funcs.commit = i9xx_crtc_commit; + } + drm_crtc_helper_add(&intel_crtc->base, &intel_helper_funcs); intel_crtc->busy = false; -- cgit v1.1 From c98e9dcf9023e72837c1c01251f370e2358a0de6 Mon Sep 17 00:00:00 2001 From: Jesse Barnes Date: Fri, 10 Sep 2010 10:57:18 -0700 Subject: drm/i915: enable PCH PLL, FDI training and transcoder even for eDP eDP panels require these to be set up prior to panel power sequencing, or they'll fail to power on due to an "asset not ready" check. And of course, eDP panels attached to anything other than DP_A need them enabled regardless, since they'll be driven from the CPU through FDI out to the PCH. Signed-off-by: Jesse Barnes Signed-off-by: Chris Wilson --- drivers/gpu/drm/i915/intel_display.c | 242 +++++++++++++++++------------------ 1 file changed, 119 insertions(+), 123 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 98276b8..ff54919 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -1889,34 +1889,32 @@ static void ironlake_crtc_enable(struct drm_crtc *crtc) } } - if (!HAS_eDP) { - /* enable PCH FDI RX PLL, wait warmup plus DMI latency */ - temp = I915_READ(fdi_rx_reg); - /* - * make the BPC in FDI Rx be consistent with that in - * pipeconf reg. - */ - temp &= ~(0x7 << 16); - temp |= (pipe_bpc << 11); - temp &= ~(7 << 19); - temp |= (intel_crtc->fdi_lanes - 1) << 19; - I915_WRITE(fdi_rx_reg, temp | FDI_RX_PLL_ENABLE); - I915_READ(fdi_rx_reg); - udelay(200); + /* enable PCH FDI RX PLL, wait warmup plus DMI latency */ + temp = I915_READ(fdi_rx_reg); + /* + * make the BPC in FDI Rx be consistent with that in + * pipeconf reg. + */ + temp &= ~(0x7 << 16); + temp |= (pipe_bpc << 11); + temp &= ~(7 << 19); + temp |= (intel_crtc->fdi_lanes - 1) << 19; + I915_WRITE(fdi_rx_reg, temp | FDI_RX_PLL_ENABLE); + I915_READ(fdi_rx_reg); + udelay(200); - /* Switch from Rawclk to PCDclk */ - temp = I915_READ(fdi_rx_reg); - I915_WRITE(fdi_rx_reg, temp | FDI_SEL_PCDCLK); - I915_READ(fdi_rx_reg); - udelay(200); + /* Switch from Rawclk to PCDclk */ + temp = I915_READ(fdi_rx_reg); + I915_WRITE(fdi_rx_reg, temp | FDI_SEL_PCDCLK); + I915_READ(fdi_rx_reg); + udelay(200); - /* Enable CPU FDI TX PLL, always on for Ironlake */ - temp = I915_READ(fdi_tx_reg); - if ((temp & FDI_TX_PLL_ENABLE) == 0) { - I915_WRITE(fdi_tx_reg, temp | FDI_TX_PLL_ENABLE); - I915_READ(fdi_tx_reg); - udelay(100); - } + /* Enable CPU FDI TX PLL, always on for Ironlake */ + temp = I915_READ(fdi_tx_reg); + if ((temp & FDI_TX_PLL_ENABLE) == 0) { + I915_WRITE(fdi_tx_reg, temp | FDI_TX_PLL_ENABLE); + I915_READ(fdi_tx_reg); + udelay(100); } /* Enable panel fitting for LVDS */ @@ -1951,115 +1949,113 @@ static void ironlake_crtc_enable(struct drm_crtc *crtc) I915_WRITE(dspbase_reg, I915_READ(dspbase_reg)); } - if (!HAS_eDP) { - /* For PCH output, training FDI link */ - if (IS_GEN6(dev)) - gen6_fdi_link_train(crtc); - else - ironlake_fdi_link_train(crtc); + /* For PCH output, training FDI link */ + if (IS_GEN6(dev)) + gen6_fdi_link_train(crtc); + else + ironlake_fdi_link_train(crtc); - /* enable PCH DPLL */ - temp = I915_READ(pch_dpll_reg); - if ((temp & DPLL_VCO_ENABLE) == 0) { - I915_WRITE(pch_dpll_reg, temp | DPLL_VCO_ENABLE); - I915_READ(pch_dpll_reg); - } - udelay(200); + /* enable PCH DPLL */ + temp = I915_READ(pch_dpll_reg); + if ((temp & DPLL_VCO_ENABLE) == 0) { + I915_WRITE(pch_dpll_reg, temp | DPLL_VCO_ENABLE); + I915_READ(pch_dpll_reg); + } + udelay(200); - if (HAS_PCH_CPT(dev)) { - /* Be sure PCH DPLL SEL is set */ - temp = I915_READ(PCH_DPLL_SEL); - if (trans_dpll_sel == 0 && - (temp & TRANSA_DPLL_ENABLE) == 0) - temp |= (TRANSA_DPLL_ENABLE | TRANSA_DPLLA_SEL); - else if (trans_dpll_sel == 1 && - (temp & TRANSB_DPLL_ENABLE) == 0) - temp |= (TRANSB_DPLL_ENABLE | TRANSB_DPLLB_SEL); - I915_WRITE(PCH_DPLL_SEL, temp); - I915_READ(PCH_DPLL_SEL); - } - /* set transcoder timing */ - I915_WRITE(trans_htot_reg, I915_READ(cpu_htot_reg)); - I915_WRITE(trans_hblank_reg, I915_READ(cpu_hblank_reg)); - I915_WRITE(trans_hsync_reg, I915_READ(cpu_hsync_reg)); + if (HAS_PCH_CPT(dev)) { + /* Be sure PCH DPLL SEL is set */ + temp = I915_READ(PCH_DPLL_SEL); + if (trans_dpll_sel == 0 && + (temp & TRANSA_DPLL_ENABLE) == 0) + temp |= (TRANSA_DPLL_ENABLE | TRANSA_DPLLA_SEL); + else if (trans_dpll_sel == 1 && + (temp & TRANSB_DPLL_ENABLE) == 0) + temp |= (TRANSB_DPLL_ENABLE | TRANSB_DPLLB_SEL); + I915_WRITE(PCH_DPLL_SEL, temp); + I915_READ(PCH_DPLL_SEL); + } + /* set transcoder timing */ + I915_WRITE(trans_htot_reg, I915_READ(cpu_htot_reg)); + I915_WRITE(trans_hblank_reg, I915_READ(cpu_hblank_reg)); + I915_WRITE(trans_hsync_reg, I915_READ(cpu_hsync_reg)); - I915_WRITE(trans_vtot_reg, I915_READ(cpu_vtot_reg)); - I915_WRITE(trans_vblank_reg, I915_READ(cpu_vblank_reg)); - I915_WRITE(trans_vsync_reg, I915_READ(cpu_vsync_reg)); + I915_WRITE(trans_vtot_reg, I915_READ(cpu_vtot_reg)); + I915_WRITE(trans_vblank_reg, I915_READ(cpu_vblank_reg)); + I915_WRITE(trans_vsync_reg, I915_READ(cpu_vsync_reg)); - /* enable normal train */ - temp = I915_READ(fdi_tx_reg); - temp &= ~FDI_LINK_TRAIN_NONE; - I915_WRITE(fdi_tx_reg, temp | FDI_LINK_TRAIN_NONE | - FDI_TX_ENHANCE_FRAME_ENABLE); - I915_READ(fdi_tx_reg); + /* enable normal train */ + temp = I915_READ(fdi_tx_reg); + temp &= ~FDI_LINK_TRAIN_NONE; + I915_WRITE(fdi_tx_reg, temp | FDI_LINK_TRAIN_NONE | + FDI_TX_ENHANCE_FRAME_ENABLE); + I915_READ(fdi_tx_reg); - temp = I915_READ(fdi_rx_reg); - if (HAS_PCH_CPT(dev)) { - temp &= ~FDI_LINK_TRAIN_PATTERN_MASK_CPT; - temp |= FDI_LINK_TRAIN_NORMAL_CPT; - } else { - temp &= ~FDI_LINK_TRAIN_NONE; - temp |= FDI_LINK_TRAIN_NONE; - } - I915_WRITE(fdi_rx_reg, temp | FDI_RX_ENHANCE_FRAME_ENABLE); - I915_READ(fdi_rx_reg); + temp = I915_READ(fdi_rx_reg); + if (HAS_PCH_CPT(dev)) { + temp &= ~FDI_LINK_TRAIN_PATTERN_MASK_CPT; + temp |= FDI_LINK_TRAIN_NORMAL_CPT; + } else { + temp &= ~FDI_LINK_TRAIN_NONE; + temp |= FDI_LINK_TRAIN_NONE; + } + I915_WRITE(fdi_rx_reg, temp | FDI_RX_ENHANCE_FRAME_ENABLE); + I915_READ(fdi_rx_reg); - /* wait one idle pattern time */ - udelay(100); + /* wait one idle pattern time */ + udelay(100); - /* For PCH DP, enable TRANS_DP_CTL */ - if (HAS_PCH_CPT(dev) && - intel_pipe_has_type(crtc, INTEL_OUTPUT_DISPLAYPORT)) { - int trans_dp_ctl = (pipe == 0) ? TRANS_DP_CTL_A : TRANS_DP_CTL_B; - int reg; - - reg = I915_READ(trans_dp_ctl); - reg &= ~(TRANS_DP_PORT_SEL_MASK | - TRANS_DP_SYNC_MASK); - reg |= (TRANS_DP_OUTPUT_ENABLE | - TRANS_DP_ENH_FRAMING); - - if (crtc->mode.flags & DRM_MODE_FLAG_PHSYNC) - reg |= TRANS_DP_HSYNC_ACTIVE_HIGH; - if (crtc->mode.flags & DRM_MODE_FLAG_PVSYNC) - reg |= TRANS_DP_VSYNC_ACTIVE_HIGH; - - switch (intel_trans_dp_port_sel(crtc)) { - case PCH_DP_B: - reg |= TRANS_DP_PORT_SEL_B; - break; - case PCH_DP_C: - reg |= TRANS_DP_PORT_SEL_C; - break; - case PCH_DP_D: - reg |= TRANS_DP_PORT_SEL_D; - break; - default: - DRM_DEBUG_KMS("Wrong PCH DP port return. Guess port B\n"); - reg |= TRANS_DP_PORT_SEL_B; - break; - } + /* For PCH DP, enable TRANS_DP_CTL */ + if (HAS_PCH_CPT(dev) && + intel_pipe_has_type(crtc, INTEL_OUTPUT_DISPLAYPORT)) { + int trans_dp_ctl = (pipe == 0) ? TRANS_DP_CTL_A : TRANS_DP_CTL_B; + int reg; - I915_WRITE(trans_dp_ctl, reg); - POSTING_READ(trans_dp_ctl); + reg = I915_READ(trans_dp_ctl); + reg &= ~(TRANS_DP_PORT_SEL_MASK | + TRANS_DP_SYNC_MASK); + reg |= (TRANS_DP_OUTPUT_ENABLE | + TRANS_DP_ENH_FRAMING); + + if (crtc->mode.flags & DRM_MODE_FLAG_PHSYNC) + reg |= TRANS_DP_HSYNC_ACTIVE_HIGH; + if (crtc->mode.flags & DRM_MODE_FLAG_PVSYNC) + reg |= TRANS_DP_VSYNC_ACTIVE_HIGH; + + switch (intel_trans_dp_port_sel(crtc)) { + case PCH_DP_B: + reg |= TRANS_DP_PORT_SEL_B; + break; + case PCH_DP_C: + reg |= TRANS_DP_PORT_SEL_C; + break; + case PCH_DP_D: + reg |= TRANS_DP_PORT_SEL_D; + break; + default: + DRM_DEBUG_KMS("Wrong PCH DP port return. Guess port B\n"); + reg |= TRANS_DP_PORT_SEL_B; + break; } - /* enable PCH transcoder */ - temp = I915_READ(transconf_reg); - /* - * make the BPC in transcoder be consistent with - * that in pipeconf reg. - */ - temp &= ~PIPE_BPC_MASK; - temp |= pipe_bpc; - I915_WRITE(transconf_reg, temp | TRANS_ENABLE); - I915_READ(transconf_reg); - - if (wait_for(I915_READ(transconf_reg) & TRANS_STATE_ENABLE, 100)) - DRM_ERROR("failed to enable transcoder\n"); + I915_WRITE(trans_dp_ctl, reg); + POSTING_READ(trans_dp_ctl); } + /* enable PCH transcoder */ + temp = I915_READ(transconf_reg); + /* + * make the BPC in transcoder be consistent with + * that in pipeconf reg. + */ + temp &= ~PIPE_BPC_MASK; + temp |= pipe_bpc; + I915_WRITE(transconf_reg, temp | TRANS_ENABLE); + I915_READ(transconf_reg); + + if (wait_for(I915_READ(transconf_reg) & TRANS_STATE_ENABLE, 100)) + DRM_ERROR("failed to enable transcoder\n"); + intel_crtc_load_lut(crtc); intel_update_fbc(crtc, &crtc->mode); -- cgit v1.1 From 0e23b99d2599112a332136728e9250e688a08b0c Mon Sep 17 00:00:00 2001 From: Jesse Barnes Date: Fri, 10 Sep 2010 11:10:00 -0700 Subject: drm/i915: split Ironlake FDI enable function Easier to read, and will pair up with a disable function. Signed-off-by: Jesse Barnes Signed-off-by: Chris Wilson --- drivers/gpu/drm/i915/intel_display.c | 72 ++++++++++++++++++++++-------------- 1 file changed, 45 insertions(+), 27 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index ff54919..086df96 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -1848,47 +1848,21 @@ static void gen6_fdi_link_train(struct drm_crtc *crtc) DRM_DEBUG_KMS("FDI train done.\n"); } -static void ironlake_crtc_enable(struct drm_crtc *crtc) +static void ironlake_fdi_enable(struct drm_crtc *crtc) { struct drm_device *dev = crtc->dev; struct drm_i915_private *dev_priv = dev->dev_private; struct intel_crtc *intel_crtc = to_intel_crtc(crtc); int pipe = intel_crtc->pipe; - int plane = intel_crtc->plane; - int pch_dpll_reg = (pipe == 0) ? PCH_DPLL_A : PCH_DPLL_B; int pipeconf_reg = (pipe == 0) ? PIPEACONF : PIPEBCONF; - int dspcntr_reg = (plane == 0) ? DSPACNTR : DSPBCNTR; - int dspbase_reg = (plane == 0) ? DSPAADDR : DSPBADDR; int fdi_tx_reg = (pipe == 0) ? FDI_TXA_CTL : FDI_TXB_CTL; int fdi_rx_reg = (pipe == 0) ? FDI_RXA_CTL : FDI_RXB_CTL; - int transconf_reg = (pipe == 0) ? TRANSACONF : TRANSBCONF; - int cpu_htot_reg = (pipe == 0) ? HTOTAL_A : HTOTAL_B; - int cpu_hblank_reg = (pipe == 0) ? HBLANK_A : HBLANK_B; - int cpu_hsync_reg = (pipe == 0) ? HSYNC_A : HSYNC_B; - int cpu_vtot_reg = (pipe == 0) ? VTOTAL_A : VTOTAL_B; - int cpu_vblank_reg = (pipe == 0) ? VBLANK_A : VBLANK_B; - int cpu_vsync_reg = (pipe == 0) ? VSYNC_A : VSYNC_B; - int trans_htot_reg = (pipe == 0) ? TRANS_HTOTAL_A : TRANS_HTOTAL_B; - int trans_hblank_reg = (pipe == 0) ? TRANS_HBLANK_A : TRANS_HBLANK_B; - int trans_hsync_reg = (pipe == 0) ? TRANS_HSYNC_A : TRANS_HSYNC_B; - int trans_vtot_reg = (pipe == 0) ? TRANS_VTOTAL_A : TRANS_VTOTAL_B; - int trans_vblank_reg = (pipe == 0) ? TRANS_VBLANK_A : TRANS_VBLANK_B; - int trans_vsync_reg = (pipe == 0) ? TRANS_VSYNC_A : TRANS_VSYNC_B; - int trans_dpll_sel = (pipe == 0) ? 0 : 1; u32 temp; u32 pipe_bpc; temp = I915_READ(pipeconf_reg); pipe_bpc = temp & PIPE_BPC_MASK; - if (intel_pipe_has_type(crtc, INTEL_OUTPUT_LVDS)) { - temp = I915_READ(PCH_LVDS); - if ((temp & LVDS_PORT_EN) == 0) { - I915_WRITE(PCH_LVDS, temp | LVDS_PORT_EN); - POSTING_READ(PCH_LVDS); - } - } - /* enable PCH FDI RX PLL, wait warmup plus DMI latency */ temp = I915_READ(fdi_rx_reg); /* @@ -1916,6 +1890,50 @@ static void ironlake_crtc_enable(struct drm_crtc *crtc) I915_READ(fdi_tx_reg); udelay(100); } +} + +static void ironlake_crtc_enable(struct drm_crtc *crtc) +{ + struct drm_device *dev = crtc->dev; + struct drm_i915_private *dev_priv = dev->dev_private; + struct intel_crtc *intel_crtc = to_intel_crtc(crtc); + int pipe = intel_crtc->pipe; + int plane = intel_crtc->plane; + int pch_dpll_reg = (pipe == 0) ? PCH_DPLL_A : PCH_DPLL_B; + int pipeconf_reg = (pipe == 0) ? PIPEACONF : PIPEBCONF; + int dspcntr_reg = (plane == 0) ? DSPACNTR : DSPBCNTR; + int dspbase_reg = (plane == 0) ? DSPAADDR : DSPBADDR; + int fdi_tx_reg = (pipe == 0) ? FDI_TXA_CTL : FDI_TXB_CTL; + int fdi_rx_reg = (pipe == 0) ? FDI_RXA_CTL : FDI_RXB_CTL; + int transconf_reg = (pipe == 0) ? TRANSACONF : TRANSBCONF; + int cpu_htot_reg = (pipe == 0) ? HTOTAL_A : HTOTAL_B; + int cpu_hblank_reg = (pipe == 0) ? HBLANK_A : HBLANK_B; + int cpu_hsync_reg = (pipe == 0) ? HSYNC_A : HSYNC_B; + int cpu_vtot_reg = (pipe == 0) ? VTOTAL_A : VTOTAL_B; + int cpu_vblank_reg = (pipe == 0) ? VBLANK_A : VBLANK_B; + int cpu_vsync_reg = (pipe == 0) ? VSYNC_A : VSYNC_B; + int trans_htot_reg = (pipe == 0) ? TRANS_HTOTAL_A : TRANS_HTOTAL_B; + int trans_hblank_reg = (pipe == 0) ? TRANS_HBLANK_A : TRANS_HBLANK_B; + int trans_hsync_reg = (pipe == 0) ? TRANS_HSYNC_A : TRANS_HSYNC_B; + int trans_vtot_reg = (pipe == 0) ? TRANS_VTOTAL_A : TRANS_VTOTAL_B; + int trans_vblank_reg = (pipe == 0) ? TRANS_VBLANK_A : TRANS_VBLANK_B; + int trans_vsync_reg = (pipe == 0) ? TRANS_VSYNC_A : TRANS_VSYNC_B; + int trans_dpll_sel = (pipe == 0) ? 0 : 1; + u32 temp; + u32 pipe_bpc; + + temp = I915_READ(pipeconf_reg); + pipe_bpc = temp & PIPE_BPC_MASK; + + if (intel_pipe_has_type(crtc, INTEL_OUTPUT_LVDS)) { + temp = I915_READ(PCH_LVDS); + if ((temp & LVDS_PORT_EN) == 0) { + I915_WRITE(PCH_LVDS, temp | LVDS_PORT_EN); + POSTING_READ(PCH_LVDS); + } + } + + ironlake_fdi_enable(crtc); /* Enable panel fitting for LVDS */ if (dev_priv->pch_pf_size && -- cgit v1.1 From de9c27bf70964a8b257eaeb8f71f1898e9f4ac7d Mon Sep 17 00:00:00 2001 From: Jesse Barnes Date: Fri, 10 Sep 2010 11:22:02 -0700 Subject: drm/i915: don't write TU size to N1 reg TU size is only part of the M1 and M2 regs, not the N regs. This keeps us from overwriting a reserved field. Signed-off-by: Jesse Barnes Signed-off-by: Chris Wilson --- drivers/gpu/drm/i915/intel_display.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 086df96..358c301 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -4170,7 +4170,7 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc, if (HAS_PCH_SPLIT(dev)) { I915_WRITE(data_m1_reg, TU_SIZE(m_n.tu) | m_n.gmch_m); - I915_WRITE(data_n1_reg, TU_SIZE(m_n.tu) | m_n.gmch_n); + I915_WRITE(data_n1_reg, m_n.gmch_n); I915_WRITE(link_m1_reg, m_n.link_m); I915_WRITE(link_n1_reg, m_n.link_n); -- cgit v1.1 From c64e311e650921fb014af2b3c500180fc65802b9 Mon Sep 17 00:00:00 2001 From: Jesse Barnes Date: Fri, 10 Sep 2010 11:27:03 -0700 Subject: drm/i915: set FDI RX TU size to match transmit size This allows FDI error checking to work. Signed-off-by: Jesse Barnes Signed-off-by: Chris Wilson --- drivers/gpu/drm/i915/intel_display.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 358c301..c31a64d 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -1857,12 +1857,18 @@ static void ironlake_fdi_enable(struct drm_crtc *crtc) int pipeconf_reg = (pipe == 0) ? PIPEACONF : PIPEBCONF; int fdi_tx_reg = (pipe == 0) ? FDI_TXA_CTL : FDI_TXB_CTL; int fdi_rx_reg = (pipe == 0) ? FDI_RXA_CTL : FDI_RXB_CTL; + int data_m1_reg = (pipe == 0) ? PIPEA_DATA_M1 : PIPEB_DATA_M1; u32 temp; u32 pipe_bpc; + u32 tx_size; temp = I915_READ(pipeconf_reg); pipe_bpc = temp & PIPE_BPC_MASK; + /* Write the TU size bits so error detection works */ + tx_size = I915_READ(data_m1_reg) & TU_SIZE_MASK; + I915_WRITE(FDI_RXA_TUSIZE1, tx_size); + /* enable PCH FDI RX PLL, wait warmup plus DMI latency */ temp = I915_READ(fdi_rx_reg); /* -- cgit v1.1 From d5e0d2f51977fe1f7fd6ee5c1a4476b43bad8f92 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Fri, 10 Sep 2010 22:33:19 +0100 Subject: drm/i915: Ensure all PLL registers are flushed before a udelay() Signed-off-by: Chris Wilson --- drivers/gpu/drm/i915/intel_display.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index c31a64d..95c8416 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -1641,6 +1641,7 @@ static void ironlake_set_pll_edp (struct drm_crtc *crtc, int clock) dpa_ctl |= DP_PLL_FREQ_270MHZ; } I915_WRITE(DP_A, dpa_ctl); + POSTING_READ(DP_A); udelay(500); } @@ -1708,6 +1709,7 @@ static void ironlake_fdi_link_train(struct drm_crtc *crtc) temp &= ~FDI_LINK_TRAIN_NONE; temp |= FDI_LINK_TRAIN_PATTERN_2; I915_WRITE(fdi_rx_reg, temp); + POSTING_READ(fdi_rx_reg); udelay(150); tries = 0; @@ -1788,6 +1790,7 @@ static void gen6_fdi_link_train(struct drm_crtc *crtc) temp &= ~FDI_LINK_TRAIN_VOL_EMP_MASK; temp |= snb_b_fdi_train_param[i]; I915_WRITE(fdi_tx_reg, temp); + POSTING_READ(fdi_tx_reg); udelay(500); temp = I915_READ(fdi_rx_iir_reg); @@ -1823,6 +1826,7 @@ static void gen6_fdi_link_train(struct drm_crtc *crtc) temp |= FDI_LINK_TRAIN_PATTERN_2; } I915_WRITE(fdi_rx_reg, temp); + POSTING_READ(fdi_rx_reg); udelay(150); for (i = 0; i < 4; i++ ) { @@ -1830,6 +1834,7 @@ static void gen6_fdi_link_train(struct drm_crtc *crtc) temp &= ~FDI_LINK_TRAIN_VOL_EMP_MASK; temp |= snb_b_fdi_train_param[i]; I915_WRITE(fdi_tx_reg, temp); + POSTING_READ(fdi_tx_reg); udelay(500); temp = I915_READ(fdi_rx_iir_reg); -- cgit v1.1 From 8c4223bee91b771782f2ec07f2c85d81cdff3ed5 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Fri, 10 Sep 2010 22:33:42 +0100 Subject: drm/i915: Only call udelay() when waiting for clocks to stabilise Signed-off-by: Chris Wilson --- drivers/gpu/drm/i915/intel_display.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 95c8416..df410e4 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -1989,8 +1989,8 @@ static void ironlake_crtc_enable(struct drm_crtc *crtc) if ((temp & DPLL_VCO_ENABLE) == 0) { I915_WRITE(pch_dpll_reg, temp | DPLL_VCO_ENABLE); I915_READ(pch_dpll_reg); + udelay(200); } - udelay(200); if (HAS_PCH_CPT(dev)) { /* Be sure PCH DPLL SEL is set */ @@ -2136,8 +2136,6 @@ static void ironlake_crtc_disable(struct drm_crtc *crtc) } else DRM_DEBUG_KMS("crtc %d is disabled\n", pipe); - udelay(100); - /* Disable PF */ I915_WRITE(pipe ? PFB_CTL_1 : PFA_CTL_1, 0); I915_WRITE(pipe ? PFB_WIN_SZ : PFA_WIN_SZ, 0); -- cgit v1.1 From 021357acc8ea85273a9882b3fe89935629f51b12 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Tue, 7 Sep 2010 20:54:59 +0100 Subject: drm/i915: Use the real FDI frequency for determining b/w Signed-off-by: Chris Wilson --- drivers/gpu/drm/i915/i915_reg.h | 1 + drivers/gpu/drm/i915/intel_display.c | 17 ++++++++++++++++- drivers/gpu/drm/i915/intel_drv.h | 3 +++ 3 files changed, 20 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index d0b4b23..fbf58e0 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -2398,6 +2398,7 @@ #define RR_HW_HIGH_POWER_FRAMES_MASK 0xff00 #define FDI_PLL_BIOS_0 0x46000 +#define FDI_PLL_FB_CLOCK_MASK 0xff #define FDI_PLL_BIOS_1 0x46004 #define FDI_PLL_BIOS_2 0x46008 #define DISPLAY_PORT_PLL_BIOS_0 0x4600c diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index df410e4..5279b0c 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -342,6 +342,13 @@ static bool intel_find_pll_ironlake_dp(const intel_limit_t *, struct drm_crtc *crtc, int target, int refclk, intel_clock_t *best_clock); +static inline u32 /* units of 100MHz */ +intel_fdi_link_freq(struct drm_device *dev) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + return (I915_READ(FDI_PLL_BIOS_0) & FDI_PLL_FB_CLOCK_MASK) + 2; +} + static const intel_limit_t intel_limits_i8xx_dvo = { .dot = { .min = I8XX_DOT_MIN, .max = I8XX_DOT_MAX }, .vco = { .min = I8XX_VCO_MIN, .max = I8XX_VCO_MAX }, @@ -3767,7 +3774,15 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc, target_clock = mode->clock; else target_clock = adjusted_mode->clock; - link_bw = 270000; + + /* FDI is a binary signal running at ~2.7GHz, encoding + * each output octet as 10 bits. The actual frequency + * is stored as a divider into a 100MHz clock, and the + * mode pixel clock is stored in units of 1KHz. + * Hence the bw of each lane in terms of the mode signal + * is: + */ + link_bw = intel_fdi_link_freq(dev) * MHz(100)/KHz(1)/10; } /* determine panel color depth */ diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index 1ada684..6c6b897 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -49,6 +49,9 @@ #define wait_for(COND, MS) _wait_for(COND, MS, 1) #define wait_for_atomic(COND, MS) _wait_for(COND, MS, 0) +#define KHz(x) (1000*x) +#define MHz(x) KHz(1000*x) + /* * Display related stuff */ -- cgit v1.1 From ea056c14a269be393468fe3734f6c2319eb23a3f Mon Sep 17 00:00:00 2001 From: Jesse Barnes Date: Fri, 10 Sep 2010 10:02:13 -0700 Subject: drm/i915: enable thermal reporting for IPS Thermal reporting may not be enabled by default on some machines, so enable the appropriate bits to allow IPS to get the data it needs from the CPU thermal device. Signed-off-by: Jesse Barnes Signed-off-by: Chris Wilson --- drivers/gpu/drm/i915/i915_reg.h | 4 ++++ drivers/gpu/drm/i915/intel_display.c | 4 ++++ 2 files changed, 8 insertions(+) diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index db22a23..27d2017 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -928,6 +928,8 @@ #define CLKCFG_MEM_800 (3 << 4) #define CLKCFG_MEM_MASK (7 << 4) +#define TSC1 0x11001 +#define TSE (1<<0) #define TR1 0x11006 #define TSFS 0x11020 #define TSFS_SLOPE_MASK 0x0000ff00 @@ -1072,6 +1074,8 @@ #define MEMSTAT_SRC_CTL_STDBY 3 #define RCPREVBSYTUPAVG 0x113b8 #define RCPREVBSYTDNAVG 0x113bc +#define PMMISC 0x11214 +#define MCPPCE_EN (1<<0) /* enable PM_MSG from PCH->MPC */ #define SDEW 0x1124c #define CSIEW0 0x11250 #define CSIEW1 0x11254 diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 2e9191d..c6b8292 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -5635,6 +5635,10 @@ void ironlake_enable_drps(struct drm_device *dev) u32 rgvmodectl = I915_READ(MEMMODECTL); u8 fmax, fmin, fstart, vstart; + /* Enable temp reporting */ + I915_WRITE16(PMMISC, I915_READ(PMMISC) | MCPPCE_EN); + I915_WRITE16(TSC1, I915_READ(TSC1) | TSE); + /* 100ms RC evaluation intervals */ I915_WRITE(RCUPEI, 100000); I915_WRITE(RCDNEI, 100000); -- cgit v1.1 From bed4a6734b5f56ffd240fdda755b6eb589d32482 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Sat, 11 Sep 2010 10:47:47 +0100 Subject: drm/i915: Fix updating FBC We need to track different state on each generation in order to detect when we need to refresh the FBC registers. Signed-off-by: Chris Wilson --- drivers/gpu/drm/i915/i915_debugfs.c | 3 + drivers/gpu/drm/i915/i915_drv.h | 3 + drivers/gpu/drm/i915/intel_display.c | 152 +++++++++++++++++++---------------- 3 files changed, 90 insertions(+), 68 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_debugfs.c b/drivers/gpu/drm/i915/i915_debugfs.c index 3d882b7..fb5c2a6 100644 --- a/drivers/gpu/drm/i915/i915_debugfs.c +++ b/drivers/gpu/drm/i915/i915_debugfs.c @@ -719,6 +719,9 @@ static int i915_fbc_status(struct seq_file *m, void *unused) } else { seq_printf(m, "FBC disabled: "); switch (dev_priv->no_fbc_reason) { + case FBC_NO_OUTPUT: + seq_printf(m, "no outputs"); + break; case FBC_STOLEN_TOO_SMALL: seq_printf(m, "not enough stolen memory"); break; diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index c8b2200..b3efb30 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -219,6 +219,7 @@ struct intel_device_info { }; enum no_fbc_reason { + FBC_NO_OUTPUT, /* no outputs enabled to compress */ FBC_STOLEN_TOO_SMALL, /* not enough space to hold compressed buffers */ FBC_UNSUPPORTED_MODE, /* interlace or doublescanned mode */ FBC_MODE_TOO_LARGE, /* mode too large for compression */ @@ -307,8 +308,10 @@ typedef struct drm_i915_private { unsigned long cfb_size; unsigned long cfb_pitch; + unsigned long cfb_offset; int cfb_fence; int cfb_plane; + int cfb_y; int irq_enabled; diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index c6b8292..f48e944 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -1047,7 +1047,6 @@ void intel_wait_for_vblank_off(struct drm_device *dev, int pipe) DRM_DEBUG_KMS("vblank wait timed out\n"); } -/* Parameters have changed, update FBC info */ static void i8xx_enable_fbc(struct drm_crtc *crtc, unsigned long interval) { struct drm_device *dev = crtc->dev; @@ -1059,6 +1058,14 @@ static void i8xx_enable_fbc(struct drm_crtc *crtc, unsigned long interval) int plane, i; u32 fbc_ctl, fbc_ctl2; + if (fb->pitch == dev_priv->cfb_pitch && + obj_priv->fence_reg == dev_priv->cfb_fence && + intel_crtc->plane == dev_priv->cfb_plane && + I915_READ(FBC_CONTROL) & FBC_CTL_EN) + return; + + i8xx_disable_fbc(dev); + dev_priv->cfb_pitch = dev_priv->cfb_size / FBC_LL_SIZE; if (fb->pitch < dev_priv->cfb_pitch) @@ -1100,12 +1107,6 @@ void i8xx_disable_fbc(struct drm_device *dev) struct drm_i915_private *dev_priv = dev->dev_private; u32 fbc_ctl; - if (!I915_HAS_FBC(dev)) - return; - - if (!(I915_READ(FBC_CONTROL) & FBC_CTL_EN)) - return; /* Already off, just return */ - /* Disable compression */ fbc_ctl = I915_READ(FBC_CONTROL); fbc_ctl &= ~FBC_CTL_EN; @@ -1140,9 +1141,23 @@ static void g4x_enable_fbc(struct drm_crtc *crtc, unsigned long interval) unsigned long stall_watermark = 200; u32 dpfc_ctl; + dpfc_ctl = I915_READ(DPFC_CONTROL); + if (dpfc_ctl & DPFC_CTL_EN) { + if (dev_priv->cfb_pitch == dev_priv->cfb_pitch / 64 - 1 && + dev_priv->cfb_fence == obj_priv->fence_reg && + dev_priv->cfb_plane == intel_crtc->plane && + dev_priv->cfb_y == crtc->y) + return; + + I915_WRITE(DPFC_CONTROL, dpfc_ctl & ~DPFC_CTL_EN); + POSTING_READ(DPFC_CONTROL); + intel_wait_for_vblank(dev, intel_crtc->pipe); + } + dev_priv->cfb_pitch = (dev_priv->cfb_pitch / 64) - 1; dev_priv->cfb_fence = obj_priv->fence_reg; dev_priv->cfb_plane = intel_crtc->plane; + dev_priv->cfb_y = crtc->y; dpfc_ctl = plane | DPFC_SR_EN | DPFC_CTL_LIMIT_1X; if (obj_priv->tiling_mode != I915_TILING_NONE) { @@ -1152,7 +1167,6 @@ static void g4x_enable_fbc(struct drm_crtc *crtc, unsigned long interval) I915_WRITE(DPFC_CHICKEN, ~DPFC_HT_MODIFY); } - I915_WRITE(DPFC_CONTROL, dpfc_ctl); I915_WRITE(DPFC_RECOMP_CTL, DPFC_RECOMP_STALL_EN | (stall_watermark << DPFC_RECOMP_STALL_WM_SHIFT) | (interval << DPFC_RECOMP_TIMER_COUNT_SHIFT)); @@ -1171,10 +1185,12 @@ void g4x_disable_fbc(struct drm_device *dev) /* Disable compression */ dpfc_ctl = I915_READ(DPFC_CONTROL); - dpfc_ctl &= ~DPFC_CTL_EN; - I915_WRITE(DPFC_CONTROL, dpfc_ctl); + if (dpfc_ctl & DPFC_CTL_EN) { + dpfc_ctl &= ~DPFC_CTL_EN; + I915_WRITE(DPFC_CONTROL, dpfc_ctl); - DRM_DEBUG_KMS("disabled FBC\n"); + DRM_DEBUG_KMS("disabled FBC\n"); + } } static bool g4x_fbc_enabled(struct drm_device *dev) @@ -1197,11 +1213,26 @@ static void ironlake_enable_fbc(struct drm_crtc *crtc, unsigned long interval) unsigned long stall_watermark = 200; u32 dpfc_ctl; + dpfc_ctl = I915_READ(ILK_DPFC_CONTROL); + if (dpfc_ctl & DPFC_CTL_EN) { + if (dev_priv->cfb_pitch == dev_priv->cfb_pitch / 64 - 1 && + dev_priv->cfb_fence == obj_priv->fence_reg && + dev_priv->cfb_plane == intel_crtc->plane && + dev_priv->cfb_offset == obj_priv->gtt_offset && + dev_priv->cfb_y == crtc->y) + return; + + I915_WRITE(ILK_DPFC_CONTROL, dpfc_ctl & ~DPFC_CTL_EN); + POSTING_READ(ILK_DPFC_CONTROL); + intel_wait_for_vblank(dev, intel_crtc->pipe); + } + dev_priv->cfb_pitch = (dev_priv->cfb_pitch / 64) - 1; dev_priv->cfb_fence = obj_priv->fence_reg; dev_priv->cfb_plane = intel_crtc->plane; + dev_priv->cfb_offset = obj_priv->gtt_offset; + dev_priv->cfb_y = crtc->y; - dpfc_ctl = I915_READ(ILK_DPFC_CONTROL); dpfc_ctl &= DPFC_RESERVED; dpfc_ctl |= (plane | DPFC_CTL_LIMIT_1X); if (obj_priv->tiling_mode != I915_TILING_NONE) { @@ -1211,15 +1242,13 @@ static void ironlake_enable_fbc(struct drm_crtc *crtc, unsigned long interval) I915_WRITE(ILK_DPFC_CHICKEN, ~DPFC_HT_MODIFY); } - I915_WRITE(ILK_DPFC_CONTROL, dpfc_ctl); I915_WRITE(ILK_DPFC_RECOMP_CTL, DPFC_RECOMP_STALL_EN | (stall_watermark << DPFC_RECOMP_STALL_WM_SHIFT) | (interval << DPFC_RECOMP_TIMER_COUNT_SHIFT)); I915_WRITE(ILK_DPFC_FENCE_YOFF, crtc->y); I915_WRITE(ILK_FBC_RT_BASE, obj_priv->gtt_offset | ILK_FBC_RT_VALID); /* enable it... */ - I915_WRITE(ILK_DPFC_CONTROL, I915_READ(ILK_DPFC_CONTROL) | - DPFC_CTL_EN); + I915_WRITE(ILK_DPFC_CONTROL, dpfc_ctl | DPFC_CTL_EN); DRM_DEBUG_KMS("enabled fbc on plane %d\n", intel_crtc->plane); } @@ -1231,10 +1260,12 @@ void ironlake_disable_fbc(struct drm_device *dev) /* Disable compression */ dpfc_ctl = I915_READ(ILK_DPFC_CONTROL); - dpfc_ctl &= ~DPFC_CTL_EN; - I915_WRITE(ILK_DPFC_CONTROL, dpfc_ctl); + if (dpfc_ctl & DPFC_CTL_EN) { + dpfc_ctl &= ~DPFC_CTL_EN; + I915_WRITE(ILK_DPFC_CONTROL, dpfc_ctl); - DRM_DEBUG_KMS("disabled FBC\n"); + DRM_DEBUG_KMS("disabled FBC\n"); + } } static bool ironlake_fbc_enabled(struct drm_device *dev) @@ -1276,8 +1307,7 @@ void intel_disable_fbc(struct drm_device *dev) /** * intel_update_fbc - enable/disable FBC as needed - * @crtc: CRTC to point the compressor at - * @mode: mode in use + * @dev: the drm_device * * Set up the framebuffer compression hardware at mode set time. We * enable it if possible: @@ -1294,18 +1324,14 @@ void intel_disable_fbc(struct drm_device *dev) * * We need to enable/disable FBC on a global basis. */ -static void intel_update_fbc(struct drm_crtc *crtc, - struct drm_display_mode *mode) +static void intel_update_fbc(struct drm_device *dev) { - struct drm_device *dev = crtc->dev; struct drm_i915_private *dev_priv = dev->dev_private; - struct drm_framebuffer *fb = crtc->fb; + struct drm_crtc *crtc = NULL, *tmp_crtc; + struct intel_crtc *intel_crtc; + struct drm_framebuffer *fb; struct intel_framebuffer *intel_fb; struct drm_i915_gem_object *obj_priv; - struct drm_crtc *tmp_crtc; - struct intel_crtc *intel_crtc = to_intel_crtc(crtc); - int plane = intel_crtc->plane; - int crtcs_enabled = 0; DRM_DEBUG_KMS("\n"); @@ -1315,12 +1341,6 @@ static void intel_update_fbc(struct drm_crtc *crtc, if (!I915_HAS_FBC(dev)) return; - if (!crtc->fb) - return; - - intel_fb = to_intel_framebuffer(fb); - obj_priv = to_intel_bo(intel_fb->obj); - /* * If FBC is already on, we just have to verify that we can * keep it that way... @@ -1331,35 +1351,47 @@ static void intel_update_fbc(struct drm_crtc *crtc, * - going to an unsupported config (interlace, pixel multiply, etc.) */ list_for_each_entry(tmp_crtc, &dev->mode_config.crtc_list, head) { - if (tmp_crtc->enabled) - crtcs_enabled++; + if (tmp_crtc->enabled) { + if (crtc) { + DRM_DEBUG_KMS("more than one pipe active, disabling compression\n"); + dev_priv->no_fbc_reason = FBC_MULTIPLE_PIPES; + goto out_disable; + } + crtc = tmp_crtc; + } } - DRM_DEBUG_KMS("%d pipes active\n", crtcs_enabled); - if (crtcs_enabled > 1) { - DRM_DEBUG_KMS("more than one pipe active, disabling compression\n"); - dev_priv->no_fbc_reason = FBC_MULTIPLE_PIPES; + + if (!crtc || crtc->fb == NULL) { + DRM_DEBUG_KMS("no output, disabling\n"); + dev_priv->no_fbc_reason = FBC_NO_OUTPUT; goto out_disable; } + + intel_crtc = to_intel_crtc(crtc); + fb = crtc->fb; + intel_fb = to_intel_framebuffer(fb); + obj_priv = to_intel_bo(intel_fb->obj); + if (intel_fb->obj->size > dev_priv->cfb_size) { DRM_DEBUG_KMS("framebuffer too large, disabling " "compression\n"); dev_priv->no_fbc_reason = FBC_STOLEN_TOO_SMALL; goto out_disable; } - if ((mode->flags & DRM_MODE_FLAG_INTERLACE) || - (mode->flags & DRM_MODE_FLAG_DBLSCAN)) { + if ((crtc->mode.flags & DRM_MODE_FLAG_INTERLACE) || + (crtc->mode.flags & DRM_MODE_FLAG_DBLSCAN)) { DRM_DEBUG_KMS("mode incompatible with compression, " "disabling\n"); dev_priv->no_fbc_reason = FBC_UNSUPPORTED_MODE; goto out_disable; } - if ((mode->hdisplay > 2048) || - (mode->vdisplay > 1536)) { + if ((crtc->mode.hdisplay > 2048) || + (crtc->mode.vdisplay > 1536)) { DRM_DEBUG_KMS("mode too large for compression, disabling\n"); dev_priv->no_fbc_reason = FBC_MODE_TOO_LARGE; goto out_disable; } - if ((IS_I915GM(dev) || IS_I945GM(dev)) && plane != 0) { + if ((IS_I915GM(dev) || IS_I945GM(dev)) && intel_crtc->plane != 0) { DRM_DEBUG_KMS("plane not 0, disabling compression\n"); dev_priv->no_fbc_reason = FBC_BAD_PLANE; goto out_disable; @@ -1374,18 +1406,7 @@ static void intel_update_fbc(struct drm_crtc *crtc, if (in_dbg_master()) goto out_disable; - if (intel_fbc_enabled(dev)) { - /* We can re-enable it in this case, but need to update pitch */ - if ((fb->pitch > dev_priv->cfb_pitch) || - (obj_priv->fence_reg != dev_priv->cfb_fence) || - (plane != dev_priv->cfb_plane)) - intel_disable_fbc(dev); - } - - /* Now try to turn it back on if possible */ - if (!intel_fbc_enabled(dev)) - intel_enable_fbc(crtc, 500); - + intel_enable_fbc(crtc, 500); return; out_disable: @@ -1527,10 +1548,7 @@ intel_pipe_set_base_atomic(struct drm_crtc *crtc, struct drm_framebuffer *fb, } POSTING_READ(dspbase); - if (IS_I965G(dev) || plane == 0) - intel_update_fbc(crtc, &crtc->mode); - - intel_wait_for_vblank(dev, intel_crtc->pipe); + intel_update_fbc(dev); intel_increase_pllclock(crtc); return 0; @@ -2093,8 +2111,7 @@ static void ironlake_crtc_enable(struct drm_crtc *crtc) DRM_ERROR("failed to enable transcoder\n"); intel_crtc_load_lut(crtc); - - intel_update_fbc(crtc, &crtc->mode); + intel_update_fbc(dev); } static void ironlake_crtc_disable(struct drm_crtc *crtc) @@ -2336,9 +2353,7 @@ static void i9xx_crtc_enable(struct drm_crtc *crtc) } intel_crtc_load_lut(crtc); - - if ((IS_I965G(dev) || plane == 0)) - intel_update_fbc(crtc, &crtc->mode); + intel_update_fbc(dev); /* Give the overlay scaler a chance to enable if it's on this pipe */ intel_crtc_dpms_overlay(intel_crtc, true); @@ -2473,9 +2488,9 @@ static void intel_crtc_dpms(struct drm_crtc *crtc, int mode) dev_priv->display.dpms(crtc, mode); - if (mode == DRM_MODE_DPMS_ON) + if (mode == DRM_MODE_DPMS_ON) { intel_crtc_update_cursor(crtc); - else { + } else { /* XXX Note that this is not a complete solution, but a hack * to avoid the most frequently hit hang. */ @@ -2483,6 +2498,7 @@ static void intel_crtc_dpms(struct drm_crtc *crtc, int mode) intel_update_watermarks(dev); } + intel_update_fbc(dev); if (!dev->primary->master) return; -- cgit v1.1 From 4ed765f966c8279acc6f6bc1a5dcb0424d074b40 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Sat, 11 Sep 2010 10:46:47 +0100 Subject: drm/i915: Tidy Ironlake watermark computation Refactor the common code into seperate functions and use the MIN(large, small) buffer calculation for self-refresh watermarks. Signed-off-by: Chris Wilson --- drivers/gpu/drm/i915/i915_reg.h | 4 +- drivers/gpu/drm/i915/intel_display.c | 210 ++++++++++++++++------------------- 2 files changed, 99 insertions(+), 115 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index 27d2017..eb8cb94 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -2219,8 +2219,8 @@ #define WM1_LP_SR_EN (1<<31) #define WM1_LP_LATENCY_SHIFT 24 #define WM1_LP_LATENCY_MASK (0x7f<<24) -#define WM1_LP_FBC_LP1_MASK (0xf<<20) -#define WM1_LP_FBC_LP1_SHIFT 20 +#define WM1_LP_FBC_MASK (0xf<<20) +#define WM1_LP_FBC_SHIFT 20 #define WM1_LP_SR_MASK (0x1ff<<8) #define WM1_LP_SR_SHIFT 8 #define WM1_LP_CURSOR_MASK (0x3f) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index f48e944..3ef6d7e 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -3404,146 +3404,130 @@ static void i830_update_wm(struct drm_device *dev, int planea_clock, int unused, #define ILK_LP0_PLANE_LATENCY 700 #define ILK_LP0_CURSOR_LATENCY 1300 -static void ironlake_update_wm(struct drm_device *dev, int planea_clock, - int planeb_clock, int sr_hdisplay, int sr_htotal, - int pixel_size) +static bool ironlake_compute_wm0(struct drm_device *dev, + int pipe, + int *plane_wm, + int *cursor_wm) { - struct drm_i915_private *dev_priv = dev->dev_private; - int planea_wm, planeb_wm, cursora_wm, cursorb_wm; - int sr_wm, cursor_wm; - unsigned long line_time_us; - int sr_clock, entries_required; - u32 reg_value; - int line_count; - int planea_htotal = 0, planeb_htotal = 0; struct drm_crtc *crtc; + int htotal, hdisplay, clock, pixel_size = 0; + int line_time_us, line_count, entries; - /* Need htotal for all active display plane */ - list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { - struct intel_crtc *intel_crtc = to_intel_crtc(crtc); - if (intel_crtc->dpms_mode == DRM_MODE_DPMS_ON) { - if (intel_crtc->plane == 0) - planea_htotal = crtc->mode.htotal; - else - planeb_htotal = crtc->mode.htotal; - } - } - - /* Calculate and update the watermark for plane A */ - if (planea_clock) { - entries_required = ((planea_clock / 1000) * pixel_size * - ILK_LP0_PLANE_LATENCY) / 1000; - entries_required = DIV_ROUND_UP(entries_required, - ironlake_display_wm_info.cacheline_size); - planea_wm = entries_required + - ironlake_display_wm_info.guard_size; - - if (planea_wm > (int)ironlake_display_wm_info.max_wm) - planea_wm = ironlake_display_wm_info.max_wm; - - /* Use the large buffer method to calculate cursor watermark */ - line_time_us = (planea_htotal * 1000) / planea_clock; - - /* Use ns/us then divide to preserve precision */ - line_count = (ILK_LP0_CURSOR_LATENCY / line_time_us + 1000) / 1000; - - /* calculate the cursor watermark for cursor A */ - entries_required = line_count * 64 * pixel_size; - entries_required = DIV_ROUND_UP(entries_required, - ironlake_cursor_wm_info.cacheline_size); - cursora_wm = entries_required + ironlake_cursor_wm_info.guard_size; - if (cursora_wm > ironlake_cursor_wm_info.max_wm) - cursora_wm = ironlake_cursor_wm_info.max_wm; - - reg_value = I915_READ(WM0_PIPEA_ILK); - reg_value &= ~(WM0_PIPE_PLANE_MASK | WM0_PIPE_CURSOR_MASK); - reg_value |= (planea_wm << WM0_PIPE_PLANE_SHIFT) | - (cursora_wm & WM0_PIPE_CURSOR_MASK); - I915_WRITE(WM0_PIPEA_ILK, reg_value); - DRM_DEBUG_KMS("FIFO watermarks For pipe A - plane %d, " - "cursor: %d\n", planea_wm, cursora_wm); - } - /* Calculate and update the watermark for plane B */ - if (planeb_clock) { - entries_required = ((planeb_clock / 1000) * pixel_size * - ILK_LP0_PLANE_LATENCY) / 1000; - entries_required = DIV_ROUND_UP(entries_required, - ironlake_display_wm_info.cacheline_size); - planeb_wm = entries_required + - ironlake_display_wm_info.guard_size; - - if (planeb_wm > (int)ironlake_display_wm_info.max_wm) - planeb_wm = ironlake_display_wm_info.max_wm; + crtc = intel_get_crtc_for_pipe(dev, pipe); + if (crtc->fb == NULL || !crtc->enabled) + return false; - /* Use the large buffer method to calculate cursor watermark */ - line_time_us = (planeb_htotal * 1000) / planeb_clock; + htotal = crtc->mode.htotal; + hdisplay = crtc->mode.hdisplay; + clock = crtc->mode.clock; + pixel_size = crtc->fb->bits_per_pixel / 8; + + /* Use the small buffer method to calculate plane watermark */ + entries = ((clock * pixel_size / 1000) * ILK_LP0_PLANE_LATENCY) / 1000; + entries = DIV_ROUND_UP(entries, + ironlake_display_wm_info.cacheline_size); + *plane_wm = entries + ironlake_display_wm_info.guard_size; + if (*plane_wm > (int)ironlake_display_wm_info.max_wm) + *plane_wm = ironlake_display_wm_info.max_wm; + + /* Use the large buffer method to calculate cursor watermark */ + line_time_us = ((htotal * 1000) / clock); + line_count = (ILK_LP0_CURSOR_LATENCY / line_time_us + 1000) / 1000; + entries = line_count * 64 * pixel_size; + entries = DIV_ROUND_UP(entries, + ironlake_cursor_wm_info.cacheline_size); + *cursor_wm = entries + ironlake_cursor_wm_info.guard_size; + if (*cursor_wm > ironlake_cursor_wm_info.max_wm) + *cursor_wm = ironlake_cursor_wm_info.max_wm; - /* Use ns/us then divide to preserve precision */ - line_count = (ILK_LP0_CURSOR_LATENCY / line_time_us + 1000) / 1000; + return true; +} - /* calculate the cursor watermark for cursor B */ - entries_required = line_count * 64 * pixel_size; - entries_required = DIV_ROUND_UP(entries_required, - ironlake_cursor_wm_info.cacheline_size); - cursorb_wm = entries_required + ironlake_cursor_wm_info.guard_size; - if (cursorb_wm > ironlake_cursor_wm_info.max_wm) - cursorb_wm = ironlake_cursor_wm_info.max_wm; +static void ironlake_update_wm(struct drm_device *dev, + int planea_clock, int planeb_clock, + int sr_hdisplay, int sr_htotal, + int pixel_size) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + int plane_wm, cursor_wm, enabled; + int tmp; + + enabled = 0; + if (ironlake_compute_wm0(dev, 0, &plane_wm, &cursor_wm)) { + I915_WRITE(WM0_PIPEA_ILK, + (plane_wm << WM0_PIPE_PLANE_SHIFT) | cursor_wm); + DRM_DEBUG_KMS("FIFO watermarks For pipe A -" + " plane %d, " "cursor: %d\n", + plane_wm, cursor_wm); + enabled++; + } - reg_value = I915_READ(WM0_PIPEB_ILK); - reg_value &= ~(WM0_PIPE_PLANE_MASK | WM0_PIPE_CURSOR_MASK); - reg_value |= (planeb_wm << WM0_PIPE_PLANE_SHIFT) | - (cursorb_wm & WM0_PIPE_CURSOR_MASK); - I915_WRITE(WM0_PIPEB_ILK, reg_value); - DRM_DEBUG_KMS("FIFO watermarks For pipe B - plane %d, " - "cursor: %d\n", planeb_wm, cursorb_wm); + if (ironlake_compute_wm0(dev, 1, &plane_wm, &cursor_wm)) { + I915_WRITE(WM0_PIPEB_ILK, + (plane_wm << WM0_PIPE_PLANE_SHIFT) | cursor_wm); + DRM_DEBUG_KMS("FIFO watermarks For pipe B -" + " plane %d, cursor: %d\n", + plane_wm, cursor_wm); + enabled++; } /* * Calculate and update the self-refresh watermark only when one * display plane is used. */ - if (!planea_clock || !planeb_clock) { - + tmp = 0; + if (enabled == 1 && /* XXX disabled due to buggy implmentation? */ 0) { + unsigned long line_time_us; + int small, large, plane_fbc; + int sr_clock, entries; + int line_count, line_size; /* Read the self-refresh latency. The unit is 0.5us */ int ilk_sr_latency = I915_READ(MLTR_ILK) & ILK_SRLT_MASK; sr_clock = planea_clock ? planea_clock : planeb_clock; - line_time_us = ((sr_htotal * 1000) / sr_clock); + line_time_us = (sr_htotal * 1000) / sr_clock; /* Use ns/us then divide to preserve precision */ line_count = ((ilk_sr_latency * 500) / line_time_us + 1000) / 1000; + line_size = sr_hdisplay * pixel_size; - /* calculate the self-refresh watermark for display plane */ - entries_required = line_count * sr_hdisplay * pixel_size; - entries_required = DIV_ROUND_UP(entries_required, - ironlake_display_srwm_info.cacheline_size); - sr_wm = entries_required + - ironlake_display_srwm_info.guard_size; + /* Use the minimum of the small and large buffer method for primary */ + small = ((sr_clock * pixel_size / 1000) * (ilk_sr_latency * 500)) / 1000; + large = line_count * line_size; - /* calculate the self-refresh watermark for display cursor */ - entries_required = line_count * pixel_size * 64; - entries_required = DIV_ROUND_UP(entries_required, - ironlake_cursor_srwm_info.cacheline_size); - cursor_wm = entries_required + - ironlake_cursor_srwm_info.guard_size; + entries = DIV_ROUND_UP(min(small, large), + ironlake_display_srwm_info.cacheline_size); - /* configure watermark and enable self-refresh */ - reg_value = I915_READ(WM1_LP_ILK); - reg_value &= ~(WM1_LP_LATENCY_MASK | WM1_LP_SR_MASK | - WM1_LP_CURSOR_MASK); - reg_value |= (ilk_sr_latency << WM1_LP_LATENCY_SHIFT) | - (sr_wm << WM1_LP_SR_SHIFT) | cursor_wm; + plane_fbc = entries * 64; + plane_fbc = DIV_ROUND_UP(plane_fbc, line_size); - I915_WRITE(WM1_LP_ILK, reg_value); - DRM_DEBUG_KMS("self-refresh watermark: display plane %d " - "cursor %d\n", sr_wm, cursor_wm); + plane_wm = entries + ironlake_display_srwm_info.guard_size; + if (plane_wm > (int)ironlake_display_srwm_info.max_wm) + plane_wm = ironlake_display_srwm_info.max_wm; - } else { - /* Turn off self refresh if both pipes are enabled */ - I915_WRITE(WM1_LP_ILK, I915_READ(WM1_LP_ILK) & ~WM1_LP_SR_EN); - } + /* calculate the self-refresh watermark for display cursor */ + entries = line_count * pixel_size * 64; + entries = DIV_ROUND_UP(entries, + ironlake_cursor_srwm_info.cacheline_size); + + cursor_wm = entries + ironlake_cursor_srwm_info.guard_size; + if (cursor_wm > (int)ironlake_cursor_srwm_info.max_wm) + cursor_wm = ironlake_cursor_srwm_info.max_wm; + + /* configure watermark and enable self-refresh */ + tmp = (WM1_LP_SR_EN | + (ilk_sr_latency << WM1_LP_LATENCY_SHIFT) | + (plane_fbc << WM1_LP_FBC_SHIFT) | + (plane_wm << WM1_LP_SR_SHIFT) | + cursor_wm); + DRM_DEBUG_KMS("self-refresh watermark: display plane %d, fbc lines %d," + " cursor %d\n", plane_wm, plane_fbc, cursor_wm); + } + I915_WRITE(WM1_LP_ILK, tmp); + /* XXX setup WM2 and WM3 */ } + /** * intel_update_watermarks - update FIFO watermark values based on current modes * -- cgit v1.1 From 5eddb70ba2b8cdbbdd563f5cb04e26fdc9b017f7 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Sat, 11 Sep 2010 13:48:45 +0100 Subject: drm/i915: Use macros to switch between equivalent pipe registers The purpose is to make the code much easier to read and therefore reduce the possibility for bugs. A side effect is that it also makes it much easier for the compiler, reducing the object size by 4k -- from just a few functions! Signed-off-by: Chris Wilson --- drivers/gpu/drm/i915/i915_irq.c | 35 +- drivers/gpu/drm/i915/i915_reg.h | 97 ++-- drivers/gpu/drm/i915/intel_display.c | 912 ++++++++++++++++------------------- drivers/gpu/drm/i915/intel_overlay.c | 7 +- drivers/gpu/drm/i915/intel_tv.c | 2 +- 5 files changed, 507 insertions(+), 546 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c index 7e2b476..bc8438d 100644 --- a/drivers/gpu/drm/i915/i915_irq.c +++ b/drivers/gpu/drm/i915/i915_irq.c @@ -191,12 +191,7 @@ static int i915_pipe_enabled(struct drm_device *dev, int pipe) { drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; - unsigned long pipeconf = pipe ? PIPEBCONF : PIPEACONF; - - if (I915_READ(pipeconf) & PIPEACONF_ENABLE) - return 1; - - return 0; + return I915_READ(PIPECONF(pipe)) & PIPECONF_ENABLE; } /* Called from drm generic code, passed a 'crtc', which @@ -207,10 +202,7 @@ u32 i915_get_vblank_counter(struct drm_device *dev, int pipe) drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; unsigned long high_frame; unsigned long low_frame; - u32 high1, high2, low, count; - - high_frame = pipe ? PIPEBFRAMEHIGH : PIPEAFRAMEHIGH; - low_frame = pipe ? PIPEBFRAMEPIXEL : PIPEAFRAMEPIXEL; + u32 high1, high2, low; if (!i915_pipe_enabled(dev, pipe)) { DRM_DEBUG_DRIVER("trying to get vblank count for disabled " @@ -218,23 +210,23 @@ u32 i915_get_vblank_counter(struct drm_device *dev, int pipe) return 0; } + high_frame = pipe ? PIPEBFRAMEHIGH : PIPEAFRAMEHIGH; + low_frame = pipe ? PIPEBFRAMEPIXEL : PIPEAFRAMEPIXEL; + /* * High & low register fields aren't synchronized, so make sure * we get a low value that's stable across two reads of the high * register. */ do { - high1 = ((I915_READ(high_frame) & PIPE_FRAME_HIGH_MASK) >> - PIPE_FRAME_HIGH_SHIFT); - low = ((I915_READ(low_frame) & PIPE_FRAME_LOW_MASK) >> - PIPE_FRAME_LOW_SHIFT); - high2 = ((I915_READ(high_frame) & PIPE_FRAME_HIGH_MASK) >> - PIPE_FRAME_HIGH_SHIFT); + high1 = I915_READ(high_frame) & PIPE_FRAME_HIGH_MASK; + low = I915_READ(low_frame) & PIPE_FRAME_LOW_MASK; + high2 = I915_READ(high_frame) & PIPE_FRAME_HIGH_MASK; } while (high1 != high2); - count = (high1 << 8) | low; - - return count; + high1 >>= PIPE_FRAME_HIGH_SHIFT; + low >>= PIPE_FRAME_LOW_SHIFT; + return (high1 << 8) | low; } u32 gm45_get_vblank_counter(struct drm_device *dev, int pipe) @@ -1207,11 +1199,8 @@ int i915_enable_vblank(struct drm_device *dev, int pipe) { drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; unsigned long irqflags; - int pipeconf_reg = (pipe == 0) ? PIPEACONF : PIPEBCONF; - u32 pipeconf; - pipeconf = I915_READ(pipeconf_reg); - if (!(pipeconf & PIPEACONF_ENABLE)) + if (!i915_pipe_enabled(dev, pipe)) return -EINVAL; spin_lock_irqsave(&dev_priv->user_irq_lock, irqflags); diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index eb8cb94..fd229ab 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -25,6 +25,8 @@ #ifndef _I915_REG_H_ #define _I915_REG_H_ +#define _PIPE(pipe, a, b) ((a) + (pipe)*((b)-(a))) + /* * The Bridge device's PCI config space has information about the * fb aperture size and the amount of pre-reserved memory. @@ -605,6 +607,7 @@ #define VGA1_PD_P1_MASK (0x1f << 8) #define DPLL_A 0x06014 #define DPLL_B 0x06018 +#define DPLL(pipe) _PIPE(pipe, DPLL_A, DPLL_B) #define DPLL_VCO_ENABLE (1 << 31) #define DPLL_DVO_HIGH_SPEED (1 << 30) #define DPLL_SYNCLOCK_ENABLE (1 << 29) @@ -738,10 +741,13 @@ #define DPLL_MD_VGA_UDI_MULTIPLIER_MASK 0x0000003f #define DPLL_MD_VGA_UDI_MULTIPLIER_SHIFT 0 #define DPLL_B_MD 0x06020 /* 965+ only */ +#define DPLL_MD(pipe) _PIPE(pipe, DPLL_A_MD, DPLL_B_MD) #define FPA0 0x06040 #define FPA1 0x06044 #define FPB0 0x06048 #define FPB1 0x0604c +#define FP0(pipe) _PIPE(pipe, FPA0, FPB0) +#define FP1(pipe) _PIPE(pipe, FPA1, FPB1) #define FP_N_DIV_MASK 0x003f0000 #define FP_N_PINEVIEW_DIV_MASK 0x00ff0000 #define FP_N_DIV_SHIFT 16 @@ -1156,6 +1162,15 @@ #define PIPEBSRC 0x6101c #define BCLRPAT_B 0x61020 +#define HTOTAL(pipe) _PIPE(pipe, HTOTAL_A, HTOTAL_B) +#define HBLANK(pipe) _PIPE(pipe, HBLANK_A, HBLANK_B) +#define HSYNC(pipe) _PIPE(pipe, HSYNC_A, HSYNC_B) +#define VTOTAL(pipe) _PIPE(pipe, VTOTAL_A, VTOTAL_B) +#define VBLANK(pipe) _PIPE(pipe, VBLANK_A, VBLANK_B) +#define VSYNC(pipe) _PIPE(pipe, VSYNC_A, VSYNC_B) +#define PIPESRC(pipe) _PIPE(pipe, PIPEASRC, PIPEBSRC) +#define BCLRPAT(pipe) _PIPE(pipe, BCLRPAT_A, BCLRPAT_B) + /* VGA port control */ #define ADPA 0x61100 #define ADPA_DAC_ENABLE (1<<31) @@ -2086,15 +2101,15 @@ #define PIPEADSL 0x70000 #define DSL_LINEMASK 0x00000fff #define PIPEACONF 0x70008 -#define PIPEACONF_ENABLE (1<<31) -#define PIPEACONF_DISABLE 0 -#define PIPEACONF_DOUBLE_WIDE (1<<30) +#define PIPECONF_ENABLE (1<<31) +#define PIPECONF_DISABLE 0 +#define PIPECONF_DOUBLE_WIDE (1<<30) #define I965_PIPECONF_ACTIVE (1<<30) -#define PIPEACONF_SINGLE_WIDE 0 -#define PIPEACONF_PIPE_UNLOCKED 0 -#define PIPEACONF_PIPE_LOCKED (1<<25) -#define PIPEACONF_PALETTE 0 -#define PIPEACONF_GAMMA (1<<24) +#define PIPECONF_SINGLE_WIDE 0 +#define PIPECONF_PIPE_UNLOCKED 0 +#define PIPECONF_PIPE_LOCKED (1<<25) +#define PIPECONF_PALETTE 0 +#define PIPECONF_GAMMA (1<<24) #define PIPECONF_FORCE_BORDER (1<<25) #define PIPECONF_PROGRESSIVE (0 << 21) #define PIPECONF_INTERLACE_W_FIELD_INDICATION (6 << 21) @@ -2147,6 +2162,8 @@ #define PIPE_6BPC (2 << 5) #define PIPE_12BPC (3 << 5) +#define PIPECONF(pipe) _PIPE(pipe, PIPEACONF, PIPEBCONF) + #define DSPARB 0x70030 #define DSPARB_CSTART_MASK (0x7f << 7) #define DSPARB_CSTART_SHIFT 7 @@ -2346,6 +2363,14 @@ #define DSPASURF 0x7019C /* 965+ only */ #define DSPATILEOFF 0x701A4 /* 965+ only */ +#define DSPCNTR(plane) _PIPE(plane, DSPACNTR, DSPBCNTR) +#define DSPADDR(plane) _PIPE(plane, DSPAADDR, DSPBADDR) +#define DSPSTRIDE(plane) _PIPE(plane, DSPASTRIDE, DSPBSTRIDE) +#define DSPPOS(plane) _PIPE(plane, DSPAPOS, DSPBPOS) +#define DSPSIZE(plane) _PIPE(plane, DSPASIZE, DSPBSIZE) +#define DSPSURF(plane) _PIPE(plane, DSPASURF, DSPBSURF) +#define DSPTILEOFF(plane) _PIPE(plane, DSPATILEOFF, DSPBTILEOFF) + /* VBIOS flags */ #define SWF00 0x71410 #define SWF01 0x71414 @@ -2434,46 +2459,47 @@ #define PIPEA_DATA_M1 0x60030 #define TU_SIZE(x) (((x)-1) << 25) /* default size 64 */ #define TU_SIZE_MASK 0x7e000000 -#define PIPEA_DATA_M1_OFFSET 0 +#define PIPE_DATA_M1_OFFSET 0 #define PIPEA_DATA_N1 0x60034 -#define PIPEA_DATA_N1_OFFSET 0 +#define PIPE_DATA_N1_OFFSET 0 #define PIPEA_DATA_M2 0x60038 -#define PIPEA_DATA_M2_OFFSET 0 +#define PIPE_DATA_M2_OFFSET 0 #define PIPEA_DATA_N2 0x6003c -#define PIPEA_DATA_N2_OFFSET 0 +#define PIPE_DATA_N2_OFFSET 0 #define PIPEA_LINK_M1 0x60040 -#define PIPEA_LINK_M1_OFFSET 0 +#define PIPE_LINK_M1_OFFSET 0 #define PIPEA_LINK_N1 0x60044 -#define PIPEA_LINK_N1_OFFSET 0 +#define PIPE_LINK_N1_OFFSET 0 #define PIPEA_LINK_M2 0x60048 -#define PIPEA_LINK_M2_OFFSET 0 +#define PIPE_LINK_M2_OFFSET 0 #define PIPEA_LINK_N2 0x6004c -#define PIPEA_LINK_N2_OFFSET 0 +#define PIPE_LINK_N2_OFFSET 0 /* PIPEB timing regs are same start from 0x61000 */ #define PIPEB_DATA_M1 0x61030 -#define PIPEB_DATA_M1_OFFSET 0 #define PIPEB_DATA_N1 0x61034 -#define PIPEB_DATA_N1_OFFSET 0 #define PIPEB_DATA_M2 0x61038 -#define PIPEB_DATA_M2_OFFSET 0 #define PIPEB_DATA_N2 0x6103c -#define PIPEB_DATA_N2_OFFSET 0 #define PIPEB_LINK_M1 0x61040 -#define PIPEB_LINK_M1_OFFSET 0 #define PIPEB_LINK_N1 0x61044 -#define PIPEB_LINK_N1_OFFSET 0 #define PIPEB_LINK_M2 0x61048 -#define PIPEB_LINK_M2_OFFSET 0 #define PIPEB_LINK_N2 0x6104c -#define PIPEB_LINK_N2_OFFSET 0 + +#define PIPE_DATA_M1(pipe) _PIPE(pipe, PIPEA_DATA_M1, PIPEB_DATA_M1) +#define PIPE_DATA_N1(pipe) _PIPE(pipe, PIPEA_DATA_N1, PIPEB_DATA_N1) +#define PIPE_DATA_M2(pipe) _PIPE(pipe, PIPEA_DATA_M2, PIPEB_DATA_M2) +#define PIPE_DATA_N2(pipe) _PIPE(pipe, PIPEA_DATA_N2, PIPEB_DATA_N2) +#define PIPE_LINK_M1(pipe) _PIPE(pipe, PIPEA_LINK_M1, PIPEB_LINK_M1) +#define PIPE_LINK_N1(pipe) _PIPE(pipe, PIPEA_LINK_N1, PIPEB_LINK_N1) +#define PIPE_LINK_M2(pipe) _PIPE(pipe, PIPEA_LINK_M2, PIPEB_LINK_M2) +#define PIPE_LINK_N2(pipe) _PIPE(pipe, PIPEA_LINK_N2, PIPEB_LINK_N2) /* CPU panel fitter */ #define PFA_CTL_1 0x68080 @@ -2614,11 +2640,14 @@ #define PCH_DPLL_A 0xc6014 #define PCH_DPLL_B 0xc6018 +#define PCH_DPLL(pipe) _PIPE(pipe, PCH_DPLL_A, PCH_DPLL_B) #define PCH_FPA0 0xc6040 #define PCH_FPA1 0xc6044 #define PCH_FPB0 0xc6048 #define PCH_FPB1 0xc604c +#define PCH_FP0(pipe) _PIPE(pipe, PCH_FPA0, PCH_FPB0) +#define PCH_FP1(pipe) _PIPE(pipe, PCH_FPA1, PCH_FPB1) #define PCH_DPLL_TEST 0xc606c @@ -2704,6 +2733,13 @@ #define TRANS_VBLANK_B 0xe1010 #define TRANS_VSYNC_B 0xe1014 +#define TRANS_HTOTAL(pipe) _PIPE(pipe, TRANS_HTOTAL_A, TRANS_HTOTAL_B) +#define TRANS_HBLANK(pipe) _PIPE(pipe, TRANS_HBLANK_A, TRANS_HBLANK_B) +#define TRANS_HSYNC(pipe) _PIPE(pipe, TRANS_HSYNC_A, TRANS_HSYNC_B) +#define TRANS_VTOTAL(pipe) _PIPE(pipe, TRANS_VTOTAL_A, TRANS_VTOTAL_B) +#define TRANS_VBLANK(pipe) _PIPE(pipe, TRANS_VBLANK_A, TRANS_VBLANK_B) +#define TRANS_VSYNC(pipe) _PIPE(pipe, TRANS_VSYNC_A, TRANS_VSYNC_B) + #define TRANSB_DATA_M1 0xe1030 #define TRANSB_DATA_N1 0xe1034 #define TRANSB_DATA_M2 0xe1038 @@ -2715,6 +2751,7 @@ #define TRANSACONF 0xf0008 #define TRANSBCONF 0xf1008 +#define TRANSCONF(plane) _PIPE(plane, TRANSACONF, TRANSBCONF) #define TRANS_DISABLE (0<<31) #define TRANS_ENABLE (1<<31) #define TRANS_STATE_MASK (1<<30) @@ -2739,6 +2776,7 @@ /* CPU: FDI_TX */ #define FDI_TXA_CTL 0x60100 #define FDI_TXB_CTL 0x61100 +#define FDI_TX_CTL(pipe) _PIPE(pipe, FDI_TXA_CTL, FDI_TXB_CTL) #define FDI_TX_DISABLE (0<<31) #define FDI_TX_ENABLE (1<<31) #define FDI_LINK_TRAIN_PATTERN_1 (0<<28) @@ -2780,8 +2818,8 @@ /* FDI_RX, FDI_X is hard-wired to Transcoder_X */ #define FDI_RXA_CTL 0xf000c #define FDI_RXB_CTL 0xf100c +#define FDI_RX_CTL(pipe) _PIPE(pipe, FDI_RXA_CTL, FDI_RXB_CTL) #define FDI_RX_ENABLE (1<<31) -#define FDI_RX_DISABLE (0<<31) /* train, dp width same as FDI_TX */ #define FDI_DP_PORT_WIDTH_X8 (7<<19) #define FDI_8BPC (0<<16) @@ -2796,8 +2834,7 @@ #define FDI_FS_ERR_REPORT_ENABLE (1<<9) #define FDI_FE_ERR_REPORT_ENABLE (1<<8) #define FDI_RX_ENHANCE_FRAME_ENABLE (1<<6) -#define FDI_SEL_RAWCLK (0<<4) -#define FDI_SEL_PCDCLK (1<<4) +#define FDI_PCDCLK (1<<4) /* CPT */ #define FDI_AUTO_TRAINING (1<<10) #define FDI_LINK_TRAIN_PATTERN_1_CPT (0<<8) @@ -2812,6 +2849,9 @@ #define FDI_RXA_TUSIZE2 0xf0038 #define FDI_RXB_TUSIZE1 0xf1030 #define FDI_RXB_TUSIZE2 0xf1038 +#define FDI_RX_MISC(pipe) _PIPE(pipe, FDI_RXA_MISC, FDI_RXB_MISC) +#define FDI_RX_TUSIZE1(pipe) _PIPE(pipe, FDI_RXA_TUSIZE1, FDI_RXB_TUSIZE1) +#define FDI_RX_TUSIZE2(pipe) _PIPE(pipe, FDI_RXA_TUSIZE2, FDI_RXB_TUSIZE2) /* FDI_RX interrupt register format */ #define FDI_RX_INTER_LANE_ALIGN (1<<10) @@ -2830,6 +2870,8 @@ #define FDI_RXA_IMR 0xf0018 #define FDI_RXB_IIR 0xf1014 #define FDI_RXB_IMR 0xf1018 +#define FDI_RX_IIR(pipe) _PIPE(pipe, FDI_RXA_IIR, FDI_RXB_IIR) +#define FDI_RX_IMR(pipe) _PIPE(pipe, FDI_RXA_IMR, FDI_RXB_IMR) #define FDI_PLL_CTL_1 0xfe000 #define FDI_PLL_CTL_2 0xfe004 @@ -2949,6 +2991,7 @@ #define TRANS_DP_CTL_A 0xe0300 #define TRANS_DP_CTL_B 0xe1300 #define TRANS_DP_CTL_C 0xe2300 +#define TRANS_DP_CTL(pipe) (TRANS_DP_CTL_A + (pipe) * 0x01000) #define TRANS_DP_OUTPUT_ENABLE (1<<31) #define TRANS_DP_PORT_SEL_B (0<<29) #define TRANS_DP_PORT_SEL_C (1<<29) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 3ef6d7e..1e88ebb 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -959,26 +959,26 @@ static bool intel_find_pll_g4x_dp(const intel_limit_t *limit, struct drm_crtc *crtc, int target, int refclk, intel_clock_t *best_clock) { - intel_clock_t clock; - if (target < 200000) { - clock.p1 = 2; - clock.p2 = 10; - clock.n = 2; - clock.m1 = 23; - clock.m2 = 8; - } else { - clock.p1 = 1; - clock.p2 = 10; - clock.n = 1; - clock.m1 = 14; - clock.m2 = 2; - } - clock.m = 5 * (clock.m1 + 2) + (clock.m2 + 2); - clock.p = (clock.p1 * clock.p2); - clock.dot = 96000 * clock.m / (clock.n + 2) / clock.p; - clock.vco = 0; - memcpy(best_clock, &clock, sizeof(intel_clock_t)); - return true; + intel_clock_t clock; + if (target < 200000) { + clock.p1 = 2; + clock.p2 = 10; + clock.n = 2; + clock.m1 = 23; + clock.m2 = 8; + } else { + clock.p1 = 1; + clock.p2 = 10; + clock.n = 1; + clock.m1 = 14; + clock.m2 = 2; + } + clock.m = 5 * (clock.m1 + 2) + (clock.m2 + 2); + clock.p = (clock.p1 * clock.p2); + clock.dot = 96000 * clock.m / (clock.n + 2) / clock.p; + clock.vco = 0; + memcpy(best_clock, &clock, sizeof(intel_clock_t)); + return true; } /** @@ -1099,7 +1099,7 @@ static void i8xx_enable_fbc(struct drm_crtc *crtc, unsigned long interval) I915_WRITE(FBC_CONTROL, fbc_ctl); DRM_DEBUG_KMS("enabled FBC, pitch %ld, yoff %d, plane %d, ", - dev_priv->cfb_pitch, crtc->y, dev_priv->cfb_plane); + dev_priv->cfb_pitch, crtc->y, dev_priv->cfb_plane); } void i8xx_disable_fbc(struct drm_device *dev) @@ -1136,8 +1136,7 @@ static void g4x_enable_fbc(struct drm_crtc *crtc, unsigned long interval) struct intel_framebuffer *intel_fb = to_intel_framebuffer(fb); struct drm_i915_gem_object *obj_priv = to_intel_bo(intel_fb->obj); struct intel_crtc *intel_crtc = to_intel_crtc(crtc); - int plane = (intel_crtc->plane == 0 ? DPFC_CTL_PLANEA : - DPFC_CTL_PLANEB); + int plane = intel_crtc->plane == 0 ? DPFC_CTL_PLANEA : DPFC_CTL_PLANEB; unsigned long stall_watermark = 200; u32 dpfc_ctl; @@ -1208,8 +1207,7 @@ static void ironlake_enable_fbc(struct drm_crtc *crtc, unsigned long interval) struct intel_framebuffer *intel_fb = to_intel_framebuffer(fb); struct drm_i915_gem_object *obj_priv = to_intel_bo(intel_fb->obj); struct intel_crtc *intel_crtc = to_intel_crtc(crtc); - int plane = (intel_crtc->plane == 0) ? DPFC_CTL_PLANEA : - DPFC_CTL_PLANEB; + int plane = intel_crtc->plane == 0 ? DPFC_CTL_PLANEA : DPFC_CTL_PLANEB; unsigned long stall_watermark = 200; u32 dpfc_ctl; @@ -1374,14 +1372,14 @@ static void intel_update_fbc(struct drm_device *dev) if (intel_fb->obj->size > dev_priv->cfb_size) { DRM_DEBUG_KMS("framebuffer too large, disabling " - "compression\n"); + "compression\n"); dev_priv->no_fbc_reason = FBC_STOLEN_TOO_SMALL; goto out_disable; } if ((crtc->mode.flags & DRM_MODE_FLAG_INTERLACE) || (crtc->mode.flags & DRM_MODE_FLAG_DBLSCAN)) { DRM_DEBUG_KMS("mode incompatible with compression, " - "disabling\n"); + "disabling\n"); dev_priv->no_fbc_reason = FBC_UNSUPPORTED_MODE; goto out_disable; } @@ -1479,12 +1477,8 @@ intel_pipe_set_base_atomic(struct drm_crtc *crtc, struct drm_framebuffer *fb, struct drm_gem_object *obj; int plane = intel_crtc->plane; unsigned long Start, Offset; - int dspbase = (plane == 0 ? DSPAADDR : DSPBADDR); - int dspsurf = (plane == 0 ? DSPASURF : DSPBSURF); - int dspstride = (plane == 0) ? DSPASTRIDE : DSPBSTRIDE; - int dsptileoff = (plane == 0 ? DSPATILEOFF : DSPBTILEOFF); - int dspcntr_reg = (plane == 0) ? DSPACNTR : DSPBCNTR; u32 dspcntr; + u32 reg; switch (plane) { case 0: @@ -1499,7 +1493,8 @@ intel_pipe_set_base_atomic(struct drm_crtc *crtc, struct drm_framebuffer *fb, obj = intel_fb->obj; obj_priv = to_intel_bo(obj); - dspcntr = I915_READ(dspcntr_reg); + reg = DSPCNTR(plane); + dspcntr = I915_READ(reg); /* Mask out pixel format bits in case we change it */ dspcntr &= ~DISPPLANE_PIXFORMAT_MASK; switch (fb->bits_per_pixel) { @@ -1531,22 +1526,21 @@ intel_pipe_set_base_atomic(struct drm_crtc *crtc, struct drm_framebuffer *fb, /* must disable */ dspcntr |= DISPPLANE_TRICKLE_FEED_DISABLE; - I915_WRITE(dspcntr_reg, dspcntr); + I915_WRITE(reg, dspcntr); Start = obj_priv->gtt_offset; Offset = y * fb->pitch + x * (fb->bits_per_pixel / 8); DRM_DEBUG_KMS("Writing base %08lX %08lX %d %d %d\n", Start, Offset, x, y, fb->pitch); - I915_WRITE(dspstride, fb->pitch); + I915_WRITE(DSPSTRIDE(plane), fb->pitch); if (IS_I965G(dev)) { - I915_WRITE(dspsurf, Start); - I915_WRITE(dsptileoff, (y << 16) | x); - I915_WRITE(dspbase, Offset); - } else { - I915_WRITE(dspbase, Start + Offset); - } - POSTING_READ(dspbase); + I915_WRITE(DSPSURF(plane), Start); + I915_WRITE(DSPTILEOFF(plane), (y << 16) | x); + I915_WRITE(DSPADDR(plane), Offset); + } else + I915_WRITE(DSPADDR(plane), Start + Offset); + POSTING_READ(reg); intel_update_fbc(dev); intel_increase_pllclock(crtc); @@ -1634,7 +1628,7 @@ intel_pipe_set_base(struct drm_crtc *crtc, int x, int y, return 0; } -static void ironlake_set_pll_edp (struct drm_crtc *crtc, int clock) +static void ironlake_set_pll_edp(struct drm_crtc *crtc, int clock) { struct drm_device *dev = crtc->dev; struct drm_i915_private *dev_priv = dev->dev_private; @@ -1666,8 +1660,8 @@ static void ironlake_set_pll_edp (struct drm_crtc *crtc, int clock) dpa_ctl |= DP_PLL_FREQ_270MHZ; } I915_WRITE(DP_A, dpa_ctl); - POSTING_READ(DP_A); + POSTING_READ(DP_A); udelay(500); } @@ -1678,85 +1672,84 @@ static void ironlake_fdi_link_train(struct drm_crtc *crtc) struct drm_i915_private *dev_priv = dev->dev_private; struct intel_crtc *intel_crtc = to_intel_crtc(crtc); int pipe = intel_crtc->pipe; - int fdi_tx_reg = (pipe == 0) ? FDI_TXA_CTL : FDI_TXB_CTL; - int fdi_rx_reg = (pipe == 0) ? FDI_RXA_CTL : FDI_RXB_CTL; - int fdi_rx_iir_reg = (pipe == 0) ? FDI_RXA_IIR : FDI_RXB_IIR; - int fdi_rx_imr_reg = (pipe == 0) ? FDI_RXA_IMR : FDI_RXB_IMR; - u32 temp, tries = 0; + u32 reg, temp, tries; /* Train 1: umask FDI RX Interrupt symbol_lock and bit_lock bit for train result */ - temp = I915_READ(fdi_rx_imr_reg); + reg = FDI_RX_IMR(pipe); + temp = I915_READ(reg); temp &= ~FDI_RX_SYMBOL_LOCK; temp &= ~FDI_RX_BIT_LOCK; - I915_WRITE(fdi_rx_imr_reg, temp); - I915_READ(fdi_rx_imr_reg); + I915_WRITE(reg, temp); + I915_READ(reg); udelay(150); /* enable CPU FDI TX and PCH FDI RX */ - temp = I915_READ(fdi_tx_reg); - temp |= FDI_TX_ENABLE; + reg = FDI_TX_CTL(pipe); + temp = I915_READ(reg); temp &= ~(7 << 19); temp |= (intel_crtc->fdi_lanes - 1) << 19; temp &= ~FDI_LINK_TRAIN_NONE; temp |= FDI_LINK_TRAIN_PATTERN_1; - I915_WRITE(fdi_tx_reg, temp); - I915_READ(fdi_tx_reg); + I915_WRITE(reg, temp | FDI_TX_ENABLE); - temp = I915_READ(fdi_rx_reg); + reg = FDI_RX_CTL(pipe); + temp = I915_READ(reg); temp &= ~FDI_LINK_TRAIN_NONE; temp |= FDI_LINK_TRAIN_PATTERN_1; - I915_WRITE(fdi_rx_reg, temp | FDI_RX_ENABLE); - I915_READ(fdi_rx_reg); + I915_WRITE(reg, temp | FDI_RX_ENABLE); + + POSTING_READ(reg); udelay(150); + reg = FDI_RX_IIR(pipe); for (tries = 0; tries < 5; tries++) { - temp = I915_READ(fdi_rx_iir_reg); + temp = I915_READ(reg); DRM_DEBUG_KMS("FDI_RX_IIR 0x%x\n", temp); if ((temp & FDI_RX_BIT_LOCK)) { DRM_DEBUG_KMS("FDI train 1 done.\n"); - I915_WRITE(fdi_rx_iir_reg, - temp | FDI_RX_BIT_LOCK); + I915_WRITE(reg, temp | FDI_RX_BIT_LOCK); break; } } if (tries == 5) - DRM_DEBUG_KMS("FDI train 1 fail!\n"); + DRM_ERROR("FDI train 1 fail!\n"); /* Train 2 */ - temp = I915_READ(fdi_tx_reg); + reg = FDI_TX_CTL(pipe); + temp = I915_READ(reg); temp &= ~FDI_LINK_TRAIN_NONE; temp |= FDI_LINK_TRAIN_PATTERN_2; - I915_WRITE(fdi_tx_reg, temp); + I915_WRITE(reg, temp); - temp = I915_READ(fdi_rx_reg); + reg = FDI_RX_CTL(pipe); + temp = I915_READ(reg); temp &= ~FDI_LINK_TRAIN_NONE; temp |= FDI_LINK_TRAIN_PATTERN_2; - I915_WRITE(fdi_rx_reg, temp); - POSTING_READ(fdi_rx_reg); - udelay(150); + I915_WRITE(reg, temp); - tries = 0; + POSTING_READ(reg); + udelay(150); + reg = FDI_RX_IIR(pipe); for (tries = 0; tries < 5; tries++) { - temp = I915_READ(fdi_rx_iir_reg); + temp = I915_READ(reg); DRM_DEBUG_KMS("FDI_RX_IIR 0x%x\n", temp); if (temp & FDI_RX_SYMBOL_LOCK) { - I915_WRITE(fdi_rx_iir_reg, - temp | FDI_RX_SYMBOL_LOCK); + I915_WRITE(reg, temp | FDI_RX_SYMBOL_LOCK); DRM_DEBUG_KMS("FDI train 2 done.\n"); break; } } if (tries == 5) - DRM_DEBUG_KMS("FDI train 2 fail!\n"); + DRM_ERROR("FDI train 2 fail!\n"); DRM_DEBUG_KMS("FDI train done\n"); } -static int snb_b_fdi_train_param [] = { +static const int const snb_b_fdi_train_param [] = { FDI_LINK_TRAIN_400MV_0DB_SNB_B, FDI_LINK_TRAIN_400MV_6DB_SNB_B, FDI_LINK_TRAIN_600MV_3_5DB_SNB_B, @@ -1770,24 +1763,22 @@ static void gen6_fdi_link_train(struct drm_crtc *crtc) struct drm_i915_private *dev_priv = dev->dev_private; struct intel_crtc *intel_crtc = to_intel_crtc(crtc); int pipe = intel_crtc->pipe; - int fdi_tx_reg = (pipe == 0) ? FDI_TXA_CTL : FDI_TXB_CTL; - int fdi_rx_reg = (pipe == 0) ? FDI_RXA_CTL : FDI_RXB_CTL; - int fdi_rx_iir_reg = (pipe == 0) ? FDI_RXA_IIR : FDI_RXB_IIR; - int fdi_rx_imr_reg = (pipe == 0) ? FDI_RXA_IMR : FDI_RXB_IMR; - u32 temp, i; + u32 reg, temp, i; /* Train 1: umask FDI RX Interrupt symbol_lock and bit_lock bit for train result */ - temp = I915_READ(fdi_rx_imr_reg); + reg = FDI_RX_IMR(pipe); + temp = I915_READ(reg); temp &= ~FDI_RX_SYMBOL_LOCK; temp &= ~FDI_RX_BIT_LOCK; - I915_WRITE(fdi_rx_imr_reg, temp); - I915_READ(fdi_rx_imr_reg); + I915_WRITE(reg, temp); + + POSTING_READ(reg); udelay(150); /* enable CPU FDI TX and PCH FDI RX */ - temp = I915_READ(fdi_tx_reg); - temp |= FDI_TX_ENABLE; + reg = FDI_TX_CTL(pipe); + temp = I915_READ(reg); temp &= ~(7 << 19); temp |= (intel_crtc->fdi_lanes - 1) << 19; temp &= ~FDI_LINK_TRAIN_NONE; @@ -1795,10 +1786,10 @@ static void gen6_fdi_link_train(struct drm_crtc *crtc) temp &= ~FDI_LINK_TRAIN_VOL_EMP_MASK; /* SNB-B */ temp |= FDI_LINK_TRAIN_400MV_0DB_SNB_B; - I915_WRITE(fdi_tx_reg, temp); - I915_READ(fdi_tx_reg); + I915_WRITE(reg, temp | FDI_TX_ENABLE); - temp = I915_READ(fdi_rx_reg); + reg = FDI_RX_CTL(pipe); + temp = I915_READ(reg); if (HAS_PCH_CPT(dev)) { temp &= ~FDI_LINK_TRAIN_PATTERN_MASK_CPT; temp |= FDI_LINK_TRAIN_PATTERN_1_CPT; @@ -1806,33 +1797,37 @@ static void gen6_fdi_link_train(struct drm_crtc *crtc) temp &= ~FDI_LINK_TRAIN_NONE; temp |= FDI_LINK_TRAIN_PATTERN_1; } - I915_WRITE(fdi_rx_reg, temp | FDI_RX_ENABLE); - I915_READ(fdi_rx_reg); + I915_WRITE(reg, temp | FDI_RX_ENABLE); + + POSTING_READ(reg); udelay(150); for (i = 0; i < 4; i++ ) { - temp = I915_READ(fdi_tx_reg); + reg = FDI_TX_CTL(pipe); + temp = I915_READ(reg); temp &= ~FDI_LINK_TRAIN_VOL_EMP_MASK; temp |= snb_b_fdi_train_param[i]; - I915_WRITE(fdi_tx_reg, temp); - POSTING_READ(fdi_tx_reg); + I915_WRITE(reg, temp); + + POSTING_READ(reg); udelay(500); - temp = I915_READ(fdi_rx_iir_reg); + reg = FDI_RX_IIR(pipe); + temp = I915_READ(reg); DRM_DEBUG_KMS("FDI_RX_IIR 0x%x\n", temp); if (temp & FDI_RX_BIT_LOCK) { - I915_WRITE(fdi_rx_iir_reg, - temp | FDI_RX_BIT_LOCK); + I915_WRITE(reg, temp | FDI_RX_BIT_LOCK); DRM_DEBUG_KMS("FDI train 1 done.\n"); break; } } if (i == 4) - DRM_DEBUG_KMS("FDI train 1 fail!\n"); + DRM_ERROR("FDI train 1 fail!\n"); /* Train 2 */ - temp = I915_READ(fdi_tx_reg); + reg = FDI_TX_CTL(pipe); + temp = I915_READ(reg); temp &= ~FDI_LINK_TRAIN_NONE; temp |= FDI_LINK_TRAIN_PATTERN_2; if (IS_GEN6(dev)) { @@ -1840,9 +1835,10 @@ static void gen6_fdi_link_train(struct drm_crtc *crtc) /* SNB-B */ temp |= FDI_LINK_TRAIN_400MV_0DB_SNB_B; } - I915_WRITE(fdi_tx_reg, temp); + I915_WRITE(reg, temp); - temp = I915_READ(fdi_rx_reg); + reg = FDI_RX_CTL(pipe); + temp = I915_READ(reg); if (HAS_PCH_CPT(dev)) { temp &= ~FDI_LINK_TRAIN_PATTERN_MASK_CPT; temp |= FDI_LINK_TRAIN_PATTERN_2_CPT; @@ -1850,30 +1846,33 @@ static void gen6_fdi_link_train(struct drm_crtc *crtc) temp &= ~FDI_LINK_TRAIN_NONE; temp |= FDI_LINK_TRAIN_PATTERN_2; } - I915_WRITE(fdi_rx_reg, temp); - POSTING_READ(fdi_rx_reg); + I915_WRITE(reg, temp); + + POSTING_READ(reg); udelay(150); for (i = 0; i < 4; i++ ) { - temp = I915_READ(fdi_tx_reg); + reg = FDI_TX_CTL(pipe); + temp = I915_READ(reg); temp &= ~FDI_LINK_TRAIN_VOL_EMP_MASK; temp |= snb_b_fdi_train_param[i]; - I915_WRITE(fdi_tx_reg, temp); - POSTING_READ(fdi_tx_reg); + I915_WRITE(reg, temp); + + POSTING_READ(reg); udelay(500); - temp = I915_READ(fdi_rx_iir_reg); + reg = FDI_RX_IIR(pipe); + temp = I915_READ(reg); DRM_DEBUG_KMS("FDI_RX_IIR 0x%x\n", temp); if (temp & FDI_RX_SYMBOL_LOCK) { - I915_WRITE(fdi_rx_iir_reg, - temp | FDI_RX_SYMBOL_LOCK); + I915_WRITE(reg, temp | FDI_RX_SYMBOL_LOCK); DRM_DEBUG_KMS("FDI train 2 done.\n"); break; } } if (i == 4) - DRM_DEBUG_KMS("FDI train 2 fail!\n"); + DRM_ERROR("FDI train 2 fail!\n"); DRM_DEBUG_KMS("FDI train done.\n"); } @@ -1884,50 +1883,49 @@ static void ironlake_fdi_enable(struct drm_crtc *crtc) struct drm_i915_private *dev_priv = dev->dev_private; struct intel_crtc *intel_crtc = to_intel_crtc(crtc); int pipe = intel_crtc->pipe; - int pipeconf_reg = (pipe == 0) ? PIPEACONF : PIPEBCONF; - int fdi_tx_reg = (pipe == 0) ? FDI_TXA_CTL : FDI_TXB_CTL; - int fdi_rx_reg = (pipe == 0) ? FDI_RXA_CTL : FDI_RXB_CTL; - int data_m1_reg = (pipe == 0) ? PIPEA_DATA_M1 : PIPEB_DATA_M1; - u32 temp; - u32 pipe_bpc; - u32 tx_size; - - temp = I915_READ(pipeconf_reg); - pipe_bpc = temp & PIPE_BPC_MASK; + u32 reg, temp; /* Write the TU size bits so error detection works */ - tx_size = I915_READ(data_m1_reg) & TU_SIZE_MASK; - I915_WRITE(FDI_RXA_TUSIZE1, tx_size); + I915_WRITE(FDI_RX_TUSIZE1(pipe), + I915_READ(PIPE_DATA_M1(pipe)) & TU_SIZE_MASK); /* enable PCH FDI RX PLL, wait warmup plus DMI latency */ - temp = I915_READ(fdi_rx_reg); - /* - * make the BPC in FDI Rx be consistent with that in - * pipeconf reg. - */ - temp &= ~(0x7 << 16); - temp |= (pipe_bpc << 11); - temp &= ~(7 << 19); + reg = FDI_RX_CTL(pipe); + temp = I915_READ(reg); + temp &= ~((0x7 << 19) | (0x7 << 16)); temp |= (intel_crtc->fdi_lanes - 1) << 19; - I915_WRITE(fdi_rx_reg, temp | FDI_RX_PLL_ENABLE); - I915_READ(fdi_rx_reg); + temp |= (I915_READ(PIPECONF(pipe)) & PIPE_BPC_MASK) << 11; + I915_WRITE(reg, temp | FDI_RX_PLL_ENABLE); + + POSTING_READ(reg); udelay(200); /* Switch from Rawclk to PCDclk */ - temp = I915_READ(fdi_rx_reg); - I915_WRITE(fdi_rx_reg, temp | FDI_SEL_PCDCLK); - I915_READ(fdi_rx_reg); + temp = I915_READ(reg); + I915_WRITE(reg, temp | FDI_PCDCLK); + + POSTING_READ(reg); udelay(200); /* Enable CPU FDI TX PLL, always on for Ironlake */ - temp = I915_READ(fdi_tx_reg); + reg = FDI_TX_CTL(pipe); + temp = I915_READ(reg); if ((temp & FDI_TX_PLL_ENABLE) == 0) { - I915_WRITE(fdi_tx_reg, temp | FDI_TX_PLL_ENABLE); - I915_READ(fdi_tx_reg); + I915_WRITE(reg, temp | FDI_TX_PLL_ENABLE); + + POSTING_READ(reg); udelay(100); } } +static void intel_flush_display_plane(struct drm_device *dev, + int plane) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + u32 reg = DSPADDR(plane); + I915_WRITE(reg, I915_READ(reg)); +} + static void ironlake_crtc_enable(struct drm_crtc *crtc) { struct drm_device *dev = crtc->dev; @@ -1935,38 +1933,12 @@ static void ironlake_crtc_enable(struct drm_crtc *crtc) struct intel_crtc *intel_crtc = to_intel_crtc(crtc); int pipe = intel_crtc->pipe; int plane = intel_crtc->plane; - int pch_dpll_reg = (pipe == 0) ? PCH_DPLL_A : PCH_DPLL_B; - int pipeconf_reg = (pipe == 0) ? PIPEACONF : PIPEBCONF; - int dspcntr_reg = (plane == 0) ? DSPACNTR : DSPBCNTR; - int dspbase_reg = (plane == 0) ? DSPAADDR : DSPBADDR; - int fdi_tx_reg = (pipe == 0) ? FDI_TXA_CTL : FDI_TXB_CTL; - int fdi_rx_reg = (pipe == 0) ? FDI_RXA_CTL : FDI_RXB_CTL; - int transconf_reg = (pipe == 0) ? TRANSACONF : TRANSBCONF; - int cpu_htot_reg = (pipe == 0) ? HTOTAL_A : HTOTAL_B; - int cpu_hblank_reg = (pipe == 0) ? HBLANK_A : HBLANK_B; - int cpu_hsync_reg = (pipe == 0) ? HSYNC_A : HSYNC_B; - int cpu_vtot_reg = (pipe == 0) ? VTOTAL_A : VTOTAL_B; - int cpu_vblank_reg = (pipe == 0) ? VBLANK_A : VBLANK_B; - int cpu_vsync_reg = (pipe == 0) ? VSYNC_A : VSYNC_B; - int trans_htot_reg = (pipe == 0) ? TRANS_HTOTAL_A : TRANS_HTOTAL_B; - int trans_hblank_reg = (pipe == 0) ? TRANS_HBLANK_A : TRANS_HBLANK_B; - int trans_hsync_reg = (pipe == 0) ? TRANS_HSYNC_A : TRANS_HSYNC_B; - int trans_vtot_reg = (pipe == 0) ? TRANS_VTOTAL_A : TRANS_VTOTAL_B; - int trans_vblank_reg = (pipe == 0) ? TRANS_VBLANK_A : TRANS_VBLANK_B; - int trans_vsync_reg = (pipe == 0) ? TRANS_VSYNC_A : TRANS_VSYNC_B; - int trans_dpll_sel = (pipe == 0) ? 0 : 1; - u32 temp; - u32 pipe_bpc; - - temp = I915_READ(pipeconf_reg); - pipe_bpc = temp & PIPE_BPC_MASK; + u32 reg, temp; if (intel_pipe_has_type(crtc, INTEL_OUTPUT_LVDS)) { temp = I915_READ(PCH_LVDS); - if ((temp & LVDS_PORT_EN) == 0) { + if ((temp & LVDS_PORT_EN) == 0) I915_WRITE(PCH_LVDS, temp | LVDS_PORT_EN); - POSTING_READ(PCH_LVDS); - } } ironlake_fdi_enable(crtc); @@ -1988,19 +1960,20 @@ static void ironlake_crtc_enable(struct drm_crtc *crtc) } /* Enable CPU pipe */ - temp = I915_READ(pipeconf_reg); - if ((temp & PIPEACONF_ENABLE) == 0) { - I915_WRITE(pipeconf_reg, temp | PIPEACONF_ENABLE); - I915_READ(pipeconf_reg); + reg = PIPECONF(pipe); + temp = I915_READ(reg); + if ((temp & PIPECONF_ENABLE) == 0) { + I915_WRITE(reg, temp | PIPECONF_ENABLE); + POSTING_READ(reg); udelay(100); } /* configure and enable CPU plane */ - temp = I915_READ(dspcntr_reg); + reg = DSPCNTR(plane); + temp = I915_READ(reg); if ((temp & DISPLAY_PLANE_ENABLE) == 0) { - I915_WRITE(dspcntr_reg, temp | DISPLAY_PLANE_ENABLE); - /* Flush the plane changes */ - I915_WRITE(dspbase_reg, I915_READ(dspbase_reg)); + I915_WRITE(reg, temp | DISPLAY_PLANE_ENABLE); + intel_flush_display_plane(dev, plane); } /* For PCH output, training FDI link */ @@ -2010,42 +1983,42 @@ static void ironlake_crtc_enable(struct drm_crtc *crtc) ironlake_fdi_link_train(crtc); /* enable PCH DPLL */ - temp = I915_READ(pch_dpll_reg); + reg = PCH_DPLL(pipe); + temp = I915_READ(reg); if ((temp & DPLL_VCO_ENABLE) == 0) { - I915_WRITE(pch_dpll_reg, temp | DPLL_VCO_ENABLE); - I915_READ(pch_dpll_reg); + I915_WRITE(reg, temp | DPLL_VCO_ENABLE); + POSTING_READ(reg); udelay(200); } if (HAS_PCH_CPT(dev)) { /* Be sure PCH DPLL SEL is set */ temp = I915_READ(PCH_DPLL_SEL); - if (trans_dpll_sel == 0 && - (temp & TRANSA_DPLL_ENABLE) == 0) + if (pipe == 0 && (temp & TRANSA_DPLL_ENABLE) == 0) temp |= (TRANSA_DPLL_ENABLE | TRANSA_DPLLA_SEL); - else if (trans_dpll_sel == 1 && - (temp & TRANSB_DPLL_ENABLE) == 0) + else if (pipe == 1 && (temp & TRANSB_DPLL_ENABLE) == 0) temp |= (TRANSB_DPLL_ENABLE | TRANSB_DPLLB_SEL); I915_WRITE(PCH_DPLL_SEL, temp); - I915_READ(PCH_DPLL_SEL); } + /* set transcoder timing */ - I915_WRITE(trans_htot_reg, I915_READ(cpu_htot_reg)); - I915_WRITE(trans_hblank_reg, I915_READ(cpu_hblank_reg)); - I915_WRITE(trans_hsync_reg, I915_READ(cpu_hsync_reg)); + I915_WRITE(TRANS_HTOTAL(pipe), I915_READ(HTOTAL(pipe))); + I915_WRITE(TRANS_HBLANK(pipe), I915_READ(HBLANK(pipe))); + I915_WRITE(TRANS_HSYNC(pipe), I915_READ(HSYNC(pipe))); - I915_WRITE(trans_vtot_reg, I915_READ(cpu_vtot_reg)); - I915_WRITE(trans_vblank_reg, I915_READ(cpu_vblank_reg)); - I915_WRITE(trans_vsync_reg, I915_READ(cpu_vsync_reg)); + I915_WRITE(TRANS_VTOTAL(pipe), I915_READ(VTOTAL(pipe))); + I915_WRITE(TRANS_VBLANK(pipe), I915_READ(VBLANK(pipe))); + I915_WRITE(TRANS_VSYNC(pipe), I915_READ(VSYNC(pipe))); /* enable normal train */ - temp = I915_READ(fdi_tx_reg); + reg = FDI_TX_CTL(pipe); + temp = I915_READ(reg); temp &= ~FDI_LINK_TRAIN_NONE; - I915_WRITE(fdi_tx_reg, temp | FDI_LINK_TRAIN_NONE | - FDI_TX_ENHANCE_FRAME_ENABLE); - I915_READ(fdi_tx_reg); + temp |= FDI_LINK_TRAIN_NONE | FDI_TX_ENHANCE_FRAME_ENABLE; + I915_WRITE(reg, temp); - temp = I915_READ(fdi_rx_reg); + reg = FDI_RX_CTL(pipe); + temp = I915_READ(reg); if (HAS_PCH_CPT(dev)) { temp &= ~FDI_LINK_TRAIN_PATTERN_MASK_CPT; temp |= FDI_LINK_TRAIN_NORMAL_CPT; @@ -2053,61 +2026,57 @@ static void ironlake_crtc_enable(struct drm_crtc *crtc) temp &= ~FDI_LINK_TRAIN_NONE; temp |= FDI_LINK_TRAIN_NONE; } - I915_WRITE(fdi_rx_reg, temp | FDI_RX_ENHANCE_FRAME_ENABLE); - I915_READ(fdi_rx_reg); + I915_WRITE(reg, temp | FDI_RX_ENHANCE_FRAME_ENABLE); /* wait one idle pattern time */ + POSTING_READ(reg); udelay(100); /* For PCH DP, enable TRANS_DP_CTL */ if (HAS_PCH_CPT(dev) && intel_pipe_has_type(crtc, INTEL_OUTPUT_DISPLAYPORT)) { - int trans_dp_ctl = (pipe == 0) ? TRANS_DP_CTL_A : TRANS_DP_CTL_B; - int reg; - - reg = I915_READ(trans_dp_ctl); - reg &= ~(TRANS_DP_PORT_SEL_MASK | - TRANS_DP_SYNC_MASK); - reg |= (TRANS_DP_OUTPUT_ENABLE | - TRANS_DP_ENH_FRAMING); + reg = TRANS_DP_CTL(pipe); + temp = I915_READ(reg); + temp &= ~(TRANS_DP_PORT_SEL_MASK | + TRANS_DP_SYNC_MASK); + temp |= (TRANS_DP_OUTPUT_ENABLE | + TRANS_DP_ENH_FRAMING); if (crtc->mode.flags & DRM_MODE_FLAG_PHSYNC) - reg |= TRANS_DP_HSYNC_ACTIVE_HIGH; + temp |= TRANS_DP_HSYNC_ACTIVE_HIGH; if (crtc->mode.flags & DRM_MODE_FLAG_PVSYNC) - reg |= TRANS_DP_VSYNC_ACTIVE_HIGH; + temp |= TRANS_DP_VSYNC_ACTIVE_HIGH; switch (intel_trans_dp_port_sel(crtc)) { case PCH_DP_B: - reg |= TRANS_DP_PORT_SEL_B; + temp |= TRANS_DP_PORT_SEL_B; break; case PCH_DP_C: - reg |= TRANS_DP_PORT_SEL_C; + temp |= TRANS_DP_PORT_SEL_C; break; case PCH_DP_D: - reg |= TRANS_DP_PORT_SEL_D; + temp |= TRANS_DP_PORT_SEL_D; break; default: DRM_DEBUG_KMS("Wrong PCH DP port return. Guess port B\n"); - reg |= TRANS_DP_PORT_SEL_B; + temp |= TRANS_DP_PORT_SEL_B; break; } - I915_WRITE(trans_dp_ctl, reg); - POSTING_READ(trans_dp_ctl); + I915_WRITE(reg, temp); } /* enable PCH transcoder */ - temp = I915_READ(transconf_reg); + reg = TRANSCONF(pipe); + temp = I915_READ(reg); /* * make the BPC in transcoder be consistent with * that in pipeconf reg. */ temp &= ~PIPE_BPC_MASK; - temp |= pipe_bpc; - I915_WRITE(transconf_reg, temp | TRANS_ENABLE); - I915_READ(transconf_reg); - - if (wait_for(I915_READ(transconf_reg) & TRANS_STATE_ENABLE, 100)) + temp |= I915_READ(PIPECONF(pipe)) & PIPE_BPC_MASK; + I915_WRITE(reg, temp | TRANS_ENABLE); + if (wait_for(I915_READ(reg) & TRANS_STATE_ENABLE, 100)) DRM_ERROR("failed to enable transcoder\n"); intel_crtc_load_lut(crtc); @@ -2121,28 +2090,16 @@ static void ironlake_crtc_disable(struct drm_crtc *crtc) struct intel_crtc *intel_crtc = to_intel_crtc(crtc); int pipe = intel_crtc->pipe; int plane = intel_crtc->plane; - int pch_dpll_reg = (pipe == 0) ? PCH_DPLL_A : PCH_DPLL_B; - int pipeconf_reg = (pipe == 0) ? PIPEACONF : PIPEBCONF; - int dspcntr_reg = (plane == 0) ? DSPACNTR : DSPBCNTR; - int dspbase_reg = (plane == 0) ? DSPAADDR : DSPBADDR; - int fdi_tx_reg = (pipe == 0) ? FDI_TXA_CTL : FDI_TXB_CTL; - int fdi_rx_reg = (pipe == 0) ? FDI_RXA_CTL : FDI_RXB_CTL; - int transconf_reg = (pipe == 0) ? TRANSACONF : TRANSBCONF; - int trans_dpll_sel = (pipe == 0) ? 0 : 1; - u32 temp; - u32 pipe_bpc; - - temp = I915_READ(pipeconf_reg); - pipe_bpc = temp & PIPE_BPC_MASK; + u32 reg, temp; drm_vblank_off(dev, pipe); + /* Disable display plane */ - temp = I915_READ(dspcntr_reg); - if ((temp & DISPLAY_PLANE_ENABLE) != 0) { - I915_WRITE(dspcntr_reg, temp & ~DISPLAY_PLANE_ENABLE); - /* Flush the plane changes */ - I915_WRITE(dspbase_reg, I915_READ(dspbase_reg)); - I915_READ(dspbase_reg); + reg = DSPCNTR(plane); + temp = I915_READ(reg); + if (temp & DISPLAY_PLANE_ENABLE) { + I915_WRITE(reg, temp & ~DISPLAY_PLANE_ENABLE); + intel_flush_display_plane(dev, plane); } if (dev_priv->cfb_plane == plane && @@ -2150,42 +2107,43 @@ static void ironlake_crtc_disable(struct drm_crtc *crtc) dev_priv->display.disable_fbc(dev); /* disable cpu pipe, disable after all planes disabled */ - temp = I915_READ(pipeconf_reg); - if ((temp & PIPEACONF_ENABLE) != 0) { - I915_WRITE(pipeconf_reg, temp & ~PIPEACONF_ENABLE); - + reg = PIPECONF(pipe); + temp = I915_READ(reg); + if (temp & PIPECONF_ENABLE) { + I915_WRITE(reg, temp & ~PIPECONF_ENABLE); /* wait for cpu pipe off, pipe state */ - if (wait_for((I915_READ(pipeconf_reg) & I965_PIPECONF_ACTIVE) == 0, 50)) + if (wait_for((I915_READ(reg) & I965_PIPECONF_ACTIVE) == 0, 50)) DRM_ERROR("failed to turn off cpu pipe\n"); - } else - DRM_DEBUG_KMS("crtc %d is disabled\n", pipe); + } /* Disable PF */ I915_WRITE(pipe ? PFB_CTL_1 : PFA_CTL_1, 0); I915_WRITE(pipe ? PFB_WIN_SZ : PFA_WIN_SZ, 0); /* disable CPU FDI tx and PCH FDI rx */ - temp = I915_READ(fdi_tx_reg); - I915_WRITE(fdi_tx_reg, temp & ~FDI_TX_ENABLE); - I915_READ(fdi_tx_reg); + reg = FDI_TX_CTL(pipe); + temp = I915_READ(reg); + I915_WRITE(reg, temp & ~FDI_TX_ENABLE); + POSTING_READ(reg); - temp = I915_READ(fdi_rx_reg); - /* BPC in FDI rx is consistent with that in pipeconf */ - temp &= ~(0x07 << 16); - temp |= (pipe_bpc << 11); - I915_WRITE(fdi_rx_reg, temp & ~FDI_RX_ENABLE); - I915_READ(fdi_rx_reg); + reg = FDI_RX_CTL(pipe); + temp = I915_READ(reg); + temp &= ~(0x7 << 16); + temp |= (I915_READ(PIPECONF(pipe)) & PIPE_BPC_MASK) << 11; + I915_WRITE(reg, temp & ~FDI_RX_ENABLE); + POSTING_READ(reg); udelay(100); /* still set train pattern 1 */ - temp = I915_READ(fdi_tx_reg); + reg = FDI_TX_CTL(pipe); + temp = I915_READ(reg); temp &= ~FDI_LINK_TRAIN_NONE; temp |= FDI_LINK_TRAIN_PATTERN_1; - I915_WRITE(fdi_tx_reg, temp); - POSTING_READ(fdi_tx_reg); + I915_WRITE(reg, temp); - temp = I915_READ(fdi_rx_reg); + reg = FDI_RX_CTL(pipe); + temp = I915_READ(reg); if (HAS_PCH_CPT(dev)) { temp &= ~FDI_LINK_TRAIN_PATTERN_MASK_CPT; temp |= FDI_LINK_TRAIN_PATTERN_1_CPT; @@ -2193,80 +2151,73 @@ static void ironlake_crtc_disable(struct drm_crtc *crtc) temp &= ~FDI_LINK_TRAIN_NONE; temp |= FDI_LINK_TRAIN_PATTERN_1; } - I915_WRITE(fdi_rx_reg, temp); - POSTING_READ(fdi_rx_reg); + /* BPC in FDI rx is consistent with that in PIPECONF */ + temp &= ~(0x07 << 16); + temp |= (I915_READ(PIPECONF(pipe)) & PIPE_BPC_MASK) << 11; + I915_WRITE(reg, temp); + POSTING_READ(reg); udelay(100); if (intel_pipe_has_type(crtc, INTEL_OUTPUT_LVDS)) { temp = I915_READ(PCH_LVDS); - I915_WRITE(PCH_LVDS, temp & ~LVDS_PORT_EN); - I915_READ(PCH_LVDS); - udelay(100); + if (temp & LVDS_PORT_EN) { + I915_WRITE(PCH_LVDS, temp & ~LVDS_PORT_EN); + POSTING_READ(PCH_LVDS); + udelay(100); + } } /* disable PCH transcoder */ - temp = I915_READ(transconf_reg); - if ((temp & TRANS_ENABLE) != 0) { - I915_WRITE(transconf_reg, temp & ~TRANS_ENABLE); - + reg = TRANSCONF(plane); + temp = I915_READ(reg); + if (temp & TRANS_ENABLE) { + I915_WRITE(reg, temp & ~TRANS_ENABLE); /* wait for PCH transcoder off, transcoder state */ - if (wait_for((I915_READ(transconf_reg) & TRANS_STATE_ENABLE) == 0, 50)) + if (wait_for((I915_READ(reg) & TRANS_STATE_ENABLE) == 0, 50)) DRM_ERROR("failed to disable transcoder\n"); } - temp = I915_READ(transconf_reg); - /* BPC in transcoder is consistent with that in pipeconf */ - temp &= ~PIPE_BPC_MASK; - temp |= pipe_bpc; - I915_WRITE(transconf_reg, temp); - I915_READ(transconf_reg); - udelay(100); - if (HAS_PCH_CPT(dev)) { /* disable TRANS_DP_CTL */ - int trans_dp_ctl = (pipe == 0) ? TRANS_DP_CTL_A : TRANS_DP_CTL_B; - int reg; - - reg = I915_READ(trans_dp_ctl); - reg &= ~(TRANS_DP_OUTPUT_ENABLE | TRANS_DP_PORT_SEL_MASK); - I915_WRITE(trans_dp_ctl, reg); - POSTING_READ(trans_dp_ctl); + reg = TRANS_DP_CTL(pipe); + temp = I915_READ(reg); + temp &= ~(TRANS_DP_OUTPUT_ENABLE | TRANS_DP_PORT_SEL_MASK); + I915_WRITE(reg, temp); /* disable DPLL_SEL */ temp = I915_READ(PCH_DPLL_SEL); - if (trans_dpll_sel == 0) + if (pipe == 0) temp &= ~(TRANSA_DPLL_ENABLE | TRANSA_DPLLB_SEL); else temp &= ~(TRANSB_DPLL_ENABLE | TRANSB_DPLLB_SEL); I915_WRITE(PCH_DPLL_SEL, temp); - I915_READ(PCH_DPLL_SEL); - } /* disable PCH DPLL */ - temp = I915_READ(pch_dpll_reg); - I915_WRITE(pch_dpll_reg, temp & ~DPLL_VCO_ENABLE); - I915_READ(pch_dpll_reg); + reg = PCH_DPLL(pipe); + temp = I915_READ(reg); + I915_WRITE(reg, temp & ~DPLL_VCO_ENABLE); /* Switch from PCDclk to Rawclk */ - temp = I915_READ(fdi_rx_reg); - temp &= ~FDI_SEL_PCDCLK; - I915_WRITE(fdi_rx_reg, temp); - I915_READ(fdi_rx_reg); + reg = FDI_RX_CTL(pipe); + temp = I915_READ(reg); + I915_WRITE(reg, temp & ~FDI_PCDCLK); /* Disable CPU FDI TX PLL */ - temp = I915_READ(fdi_tx_reg); - I915_WRITE(fdi_tx_reg, temp & ~FDI_TX_PLL_ENABLE); - I915_READ(fdi_tx_reg); + reg = FDI_TX_CTL(pipe); + temp = I915_READ(reg); + I915_WRITE(reg, temp & ~FDI_TX_PLL_ENABLE); + + POSTING_READ(reg); udelay(100); - temp = I915_READ(fdi_rx_reg); - temp &= ~FDI_RX_PLL_ENABLE; - I915_WRITE(fdi_rx_reg, temp); - I915_READ(fdi_rx_reg); + reg = FDI_RX_CTL(pipe); + temp = I915_READ(reg); + I915_WRITE(reg, temp & ~FDI_RX_PLL_ENABLE); /* Wait for the clocks to turn off. */ + POSTING_READ(reg); udelay(100); } @@ -2316,40 +2267,43 @@ static void i9xx_crtc_enable(struct drm_crtc *crtc) struct intel_crtc *intel_crtc = to_intel_crtc(crtc); int pipe = intel_crtc->pipe; int plane = intel_crtc->plane; - int dpll_reg = (pipe == 0) ? DPLL_A : DPLL_B; - int dspcntr_reg = (plane == 0) ? DSPACNTR : DSPBCNTR; - int dspbase_reg = (plane == 0) ? DSPAADDR : DSPBADDR; - int pipeconf_reg = (pipe == 0) ? PIPEACONF : PIPEBCONF; - u32 temp; + u32 reg, temp; /* Enable the DPLL */ - temp = I915_READ(dpll_reg); + reg = DPLL(pipe); + temp = I915_READ(reg); if ((temp & DPLL_VCO_ENABLE) == 0) { - I915_WRITE(dpll_reg, temp); - I915_READ(dpll_reg); + I915_WRITE(reg, temp); + /* Wait for the clocks to stabilize. */ + POSTING_READ(reg); udelay(150); - I915_WRITE(dpll_reg, temp | DPLL_VCO_ENABLE); - I915_READ(dpll_reg); + + I915_WRITE(reg, temp | DPLL_VCO_ENABLE); + /* Wait for the clocks to stabilize. */ + POSTING_READ(reg); udelay(150); - I915_WRITE(dpll_reg, temp | DPLL_VCO_ENABLE); - I915_READ(dpll_reg); + + I915_WRITE(reg, temp | DPLL_VCO_ENABLE); + /* Wait for the clocks to stabilize. */ + POSTING_READ(reg); udelay(150); } /* Enable the pipe */ - temp = I915_READ(pipeconf_reg); - if ((temp & PIPEACONF_ENABLE) == 0) - I915_WRITE(pipeconf_reg, temp | PIPEACONF_ENABLE); + reg = PIPECONF(pipe); + temp = I915_READ(reg); + if ((temp & PIPECONF_ENABLE) == 0) + I915_WRITE(reg, temp | PIPECONF_ENABLE); /* Enable the plane */ - temp = I915_READ(dspcntr_reg); + reg = DSPCNTR(plane); + temp = I915_READ(reg); if ((temp & DISPLAY_PLANE_ENABLE) == 0) { - I915_WRITE(dspcntr_reg, temp | DISPLAY_PLANE_ENABLE); - /* Flush the plane changes */ - I915_WRITE(dspbase_reg, I915_READ(dspbase_reg)); + I915_WRITE(reg, temp | DISPLAY_PLANE_ENABLE); + intel_flush_display_plane(dev, plane); } intel_crtc_load_lut(crtc); @@ -2366,11 +2320,7 @@ static void i9xx_crtc_disable(struct drm_crtc *crtc) struct intel_crtc *intel_crtc = to_intel_crtc(crtc); int pipe = intel_crtc->pipe; int plane = intel_crtc->plane; - int dpll_reg = (pipe == 0) ? DPLL_A : DPLL_B; - int dspcntr_reg = (plane == 0) ? DSPACNTR : DSPBCNTR; - int dspbase_reg = (plane == 0) ? DSPAADDR : DSPBADDR; - int pipeconf_reg = (pipe == 0) ? PIPEACONF : PIPEBCONF; - u32 temp; + u32 reg, temp; /* Give the overlay scaler a chance to disable if it's on this pipe */ intel_crtc_dpms_overlay(intel_crtc, false); @@ -2381,42 +2331,42 @@ static void i9xx_crtc_disable(struct drm_crtc *crtc) dev_priv->display.disable_fbc(dev); /* Disable display plane */ - temp = I915_READ(dspcntr_reg); - if ((temp & DISPLAY_PLANE_ENABLE) != 0) { - I915_WRITE(dspcntr_reg, temp & ~DISPLAY_PLANE_ENABLE); + reg = DSPCNTR(plane); + temp = I915_READ(reg); + if (temp & DISPLAY_PLANE_ENABLE) { + I915_WRITE(reg, temp & ~DISPLAY_PLANE_ENABLE); /* Flush the plane changes */ - I915_WRITE(dspbase_reg, I915_READ(dspbase_reg)); - I915_READ(dspbase_reg); - } + intel_flush_display_plane(dev, plane); - if (!IS_I9XX(dev)) { /* Wait for vblank for the disable to take effect */ - intel_wait_for_vblank_off(dev, pipe); + if (!IS_I9XX(dev)) + intel_wait_for_vblank_off(dev, pipe); } /* Don't disable pipe A or pipe A PLLs if needed */ - if (pipeconf_reg == PIPEACONF && - (dev_priv->quirks & QUIRK_PIPEA_FORCE)) - goto skip_pipe_off; + if (pipe == 0 && (dev_priv->quirks & QUIRK_PIPEA_FORCE)) + return; /* Next, disable display pipes */ - temp = I915_READ(pipeconf_reg); - if ((temp & PIPEACONF_ENABLE) != 0) { - I915_WRITE(pipeconf_reg, temp & ~PIPEACONF_ENABLE); - I915_READ(pipeconf_reg); + reg = PIPECONF(pipe); + temp = I915_READ(reg); + if (temp & PIPECONF_ENABLE) { + I915_WRITE(reg, temp & ~PIPECONF_ENABLE); + + /* Wait for vblank for the disable to take effect. */ + POSTING_READ(reg); + intel_wait_for_vblank_off(dev, pipe); } - /* Wait for vblank for the disable to take effect. */ - intel_wait_for_vblank_off(dev, pipe); + reg = DPLL(pipe); + temp = I915_READ(reg); + if (temp & DPLL_VCO_ENABLE) { + I915_WRITE(reg, temp & ~DPLL_VCO_ENABLE); - temp = I915_READ(dpll_reg); - if ((temp & DPLL_VCO_ENABLE) != 0) { - I915_WRITE(dpll_reg, temp & ~DPLL_VCO_ENABLE); - I915_READ(dpll_reg); + /* Wait for the clocks to turn off. */ + POSTING_READ(reg); + udelay(150); } -skip_pipe_off: - /* Wait for the clocks to turn off. */ - udelay(150); } static void i9xx_crtc_dpms(struct drm_crtc *crtc, int mode) @@ -3030,7 +2980,7 @@ static int i9xx_get_fifo_size(struct drm_device *dev, int plane) size = ((dsparb >> DSPARB_CSTART_SHIFT) & 0x7f) - size; DRM_DEBUG_KMS("FIFO size - (0x%08x) %s: %d\n", dsparb, - plane ? "B" : "A", size); + plane ? "B" : "A", size); return size; } @@ -3047,7 +2997,7 @@ static int i85x_get_fifo_size(struct drm_device *dev, int plane) size >>= 1; /* Convert to cachelines */ DRM_DEBUG_KMS("FIFO size - (0x%08x) %s: %d\n", dsparb, - plane ? "B" : "A", size); + plane ? "B" : "A", size); return size; } @@ -3062,8 +3012,8 @@ static int i845_get_fifo_size(struct drm_device *dev, int plane) size >>= 2; /* Convert to cachelines */ DRM_DEBUG_KMS("FIFO size - (0x%08x) %s: %d\n", dsparb, - plane ? "B" : "A", - size); + plane ? "B" : "A", + size); return size; } @@ -3078,14 +3028,14 @@ static int i830_get_fifo_size(struct drm_device *dev, int plane) size >>= 1; /* Convert to cachelines */ DRM_DEBUG_KMS("FIFO size - (0x%08x) %s: %d\n", dsparb, - plane ? "B" : "A", size); + plane ? "B" : "A", size); return size; } static void pineview_update_wm(struct drm_device *dev, int planea_clock, - int planeb_clock, int sr_hdisplay, int unused, - int pixel_size) + int planeb_clock, int sr_hdisplay, int unused, + int pixel_size) { struct drm_i915_private *dev_priv = dev->dev_private; const struct cxsr_latency *latency; @@ -3197,13 +3147,13 @@ static void g4x_update_wm(struct drm_device *dev, int planea_clock, /* Use ns/us then divide to preserve precision */ sr_entries = (((sr_latency_ns / line_time_us) + 1000) / 1000) * - pixel_size * sr_hdisplay; + pixel_size * sr_hdisplay; sr_entries = DIV_ROUND_UP(sr_entries, cacheline_size); entries_required = (((sr_latency_ns / line_time_us) + 1000) / 1000) * pixel_size * 64; entries_required = DIV_ROUND_UP(entries_required, - g4x_cursor_wm_info.cacheline_size); + g4x_cursor_wm_info.cacheline_size); cursor_sr = entries_required + g4x_cursor_wm_info.guard_size; if (cursor_sr > g4x_cursor_wm_info.max_wm) @@ -3215,7 +3165,7 @@ static void g4x_update_wm(struct drm_device *dev, int planea_clock, } else { /* Turn off self refresh if both pipes are enabled */ I915_WRITE(FW_BLC_SELF, I915_READ(FW_BLC_SELF) - & ~FW_BLC_SELF_EN); + & ~FW_BLC_SELF_EN); } DRM_DEBUG("Setting FIFO watermarks - A: %d, B: %d, SR %d\n", @@ -3253,7 +3203,7 @@ static void i965_update_wm(struct drm_device *dev, int planea_clock, /* Use ns/us then divide to preserve precision */ sr_entries = (((sr_latency_ns / line_time_us) + 1000) / 1000) * - pixel_size * sr_hdisplay; + pixel_size * sr_hdisplay; sr_entries = DIV_ROUND_UP(sr_entries, I915_FIFO_LINE_SIZE); DRM_DEBUG("self-refresh entries: %d\n", sr_entries); srwm = I965_FIFO_SIZE - sr_entries; @@ -3262,11 +3212,11 @@ static void i965_update_wm(struct drm_device *dev, int planea_clock, srwm &= 0x1ff; sr_entries = (((sr_latency_ns / line_time_us) + 1000) / 1000) * - pixel_size * 64; + pixel_size * 64; sr_entries = DIV_ROUND_UP(sr_entries, i965_cursor_wm_info.cacheline_size); cursor_sr = i965_cursor_wm_info.fifo_size - - (sr_entries + i965_cursor_wm_info.guard_size); + (sr_entries + i965_cursor_wm_info.guard_size); if (cursor_sr > i965_cursor_wm_info.max_wm) cursor_sr = i965_cursor_wm_info.max_wm; @@ -3345,7 +3295,7 @@ static void i9xx_update_wm(struct drm_device *dev, int planea_clock, /* Use ns/us then divide to preserve precision */ sr_entries = (((sr_latency_ns / line_time_us) + 1000) / 1000) * - pixel_size * sr_hdisplay; + pixel_size * sr_hdisplay; sr_entries = DIV_ROUND_UP(sr_entries, cacheline_size); DRM_DEBUG_KMS("self-refresh entries: %d\n", sr_entries); srwm = total_size - sr_entries; @@ -3370,7 +3320,7 @@ static void i9xx_update_wm(struct drm_device *dev, int planea_clock, } DRM_DEBUG_KMS("Setting FIFO watermarks - A: %d, B: %d, C: %d, SR %d\n", - planea_wm, planeb_wm, cwm, srwm); + planea_wm, planeb_wm, cwm, srwm); fwater_lo = ((planeb_wm & 0x3f) << 16) | (planea_wm & 0x3f); fwater_hi = (cwm & 0x1f); @@ -3489,7 +3439,7 @@ static void ironlake_update_wm(struct drm_device *dev, /* Use ns/us then divide to preserve precision */ line_count = ((ilk_sr_latency * 500) / line_time_us + 1000) - / 1000; + / 1000; line_size = sr_hdisplay * pixel_size; /* Use the minimum of the small and large buffer method for primary */ @@ -3559,7 +3509,7 @@ static void ironlake_update_wm(struct drm_device *dev, * * We don't use the sprite, so we can ignore that. And on Crestline we have * to set the non-SR watermarks to 8. - */ + */ static void intel_update_watermarks(struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; @@ -3579,11 +3529,11 @@ static void intel_update_watermarks(struct drm_device *dev) enabled++; if (intel_crtc->plane == 0) { DRM_DEBUG_KMS("plane A (pipe %d) clock: %d\n", - intel_crtc->pipe, crtc->mode.clock); + intel_crtc->pipe, crtc->mode.clock); planea_clock = crtc->mode.clock; } else { DRM_DEBUG_KMS("plane B (pipe %d) clock: %d\n", - intel_crtc->pipe, crtc->mode.clock); + intel_crtc->pipe, crtc->mode.clock); planeb_clock = crtc->mode.clock; } sr_hdisplay = crtc->mode.hdisplay; @@ -3614,61 +3564,35 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc, struct intel_crtc *intel_crtc = to_intel_crtc(crtc); int pipe = intel_crtc->pipe; int plane = intel_crtc->plane; - int fp_reg = (pipe == 0) ? FPA0 : FPB0; - int dpll_reg = (pipe == 0) ? DPLL_A : DPLL_B; - int dpll_md_reg = (intel_crtc->pipe == 0) ? DPLL_A_MD : DPLL_B_MD; - int dspcntr_reg = (plane == 0) ? DSPACNTR : DSPBCNTR; - int pipeconf_reg = (pipe == 0) ? PIPEACONF : PIPEBCONF; - int htot_reg = (pipe == 0) ? HTOTAL_A : HTOTAL_B; - int hblank_reg = (pipe == 0) ? HBLANK_A : HBLANK_B; - int hsync_reg = (pipe == 0) ? HSYNC_A : HSYNC_B; - int vtot_reg = (pipe == 0) ? VTOTAL_A : VTOTAL_B; - int vblank_reg = (pipe == 0) ? VBLANK_A : VBLANK_B; - int vsync_reg = (pipe == 0) ? VSYNC_A : VSYNC_B; - int dspsize_reg = (plane == 0) ? DSPASIZE : DSPBSIZE; - int dsppos_reg = (plane == 0) ? DSPAPOS : DSPBPOS; - int pipesrc_reg = (pipe == 0) ? PIPEASRC : PIPEBSRC; + u32 fp_reg, dpll_reg; int refclk, num_connectors = 0; intel_clock_t clock, reduced_clock; - u32 dpll = 0, fp = 0, fp2 = 0, dspcntr, pipeconf; + u32 dpll, fp = 0, fp2 = 0, dspcntr, pipeconf; bool ok, has_reduced_clock = false, is_sdvo = false, is_dvo = false; bool is_crt = false, is_lvds = false, is_tv = false, is_dp = false; struct intel_encoder *has_edp_encoder = NULL; struct drm_mode_config *mode_config = &dev->mode_config; - struct drm_encoder *encoder; + struct intel_encoder *encoder; const intel_limit_t *limit; int ret; struct fdi_m_n m_n = {0}; - int data_m1_reg = (pipe == 0) ? PIPEA_DATA_M1 : PIPEB_DATA_M1; - int data_n1_reg = (pipe == 0) ? PIPEA_DATA_N1 : PIPEB_DATA_N1; - int link_m1_reg = (pipe == 0) ? PIPEA_LINK_M1 : PIPEB_LINK_M1; - int link_n1_reg = (pipe == 0) ? PIPEA_LINK_N1 : PIPEB_LINK_N1; - int pch_fp_reg = (pipe == 0) ? PCH_FPA0 : PCH_FPB0; - int pch_dpll_reg = (pipe == 0) ? PCH_DPLL_A : PCH_DPLL_B; - int fdi_rx_reg = (pipe == 0) ? FDI_RXA_CTL : FDI_RXB_CTL; - int fdi_tx_reg = (pipe == 0) ? FDI_TXA_CTL : FDI_TXB_CTL; - int trans_dpll_sel = (pipe == 0) ? 0 : 1; - int lvds_reg = LVDS; - u32 temp; + u32 reg, temp; int target_clock; drm_vblank_pre_modeset(dev, pipe); - list_for_each_entry(encoder, &mode_config->encoder_list, head) { - struct intel_encoder *intel_encoder; - - if (encoder->crtc != crtc) + list_for_each_entry(encoder, &mode_config->encoder_list, base.head) { + if (encoder->base.crtc != crtc) continue; - intel_encoder = to_intel_encoder(encoder); - switch (intel_encoder->type) { + switch (encoder->type) { case INTEL_OUTPUT_LVDS: is_lvds = true; break; case INTEL_OUTPUT_SDVO: case INTEL_OUTPUT_HDMI: is_sdvo = true; - if (intel_encoder->needs_tv_clock) + if (encoder->needs_tv_clock) is_tv = true; break; case INTEL_OUTPUT_DVO: @@ -3684,7 +3608,7 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc, is_dp = true; break; case INTEL_OUTPUT_EDP: - has_edp_encoder = intel_encoder; + has_edp_encoder = encoder; break; } @@ -3694,7 +3618,7 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc, if (is_lvds && dev_priv->lvds_use_ssc && num_connectors < 2) { refclk = dev_priv->lvds_ssc_freq * 1000; DRM_DEBUG_KMS("using SSC reference clock of %d MHz\n", - refclk / 1000); + refclk / 1000); } else if (IS_I9XX(dev)) { refclk = 96000; if (HAS_PCH_SPLIT(dev)) @@ -3702,7 +3626,6 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc, } else { refclk = 48000; } - /* * Returns a set of divisors for the desired target clock with the given @@ -3722,9 +3645,9 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc, if (is_lvds && dev_priv->lvds_downclock_avail) { has_reduced_clock = limit->find_pll(limit, crtc, - dev_priv->lvds_downclock, - refclk, - &reduced_clock); + dev_priv->lvds_downclock, + refclk, + &reduced_clock); if (has_reduced_clock && (clock.p != reduced_clock.p)) { /* * If the different P is found, it means that we can't @@ -3733,7 +3656,7 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc, * feature. */ DRM_DEBUG_KMS("Different P is found for " - "LVDS clock/downclock\n"); + "LVDS clock/downclock\n"); has_reduced_clock = 0; } } @@ -3741,14 +3664,14 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc, this mirrors vbios setting. */ if (is_sdvo && is_tv) { if (adjusted_mode->clock >= 100000 - && adjusted_mode->clock < 140500) { + && adjusted_mode->clock < 140500) { clock.p1 = 2; clock.p2 = 10; clock.n = 3; clock.m1 = 16; clock.m2 = 8; } else if (adjusted_mode->clock >= 140500 - && adjusted_mode->clock <= 200000) { + && adjusted_mode->clock <= 200000) { clock.p1 = 1; clock.p2 = 10; clock.n = 6; @@ -3785,12 +3708,11 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc, } /* determine panel color depth */ - temp = I915_READ(pipeconf_reg); + temp = I915_READ(PIPECONF(pipe)); temp &= ~PIPE_BPC_MASK; if (is_lvds) { - int lvds_reg = I915_READ(PCH_LVDS); /* the BPC will be 6 if it is 18-bit LVDS panel */ - if ((lvds_reg & LVDS_A3_POWER_MASK) == LVDS_A3_POWER_UP) + if ((I915_READ(PCH_LVDS) & LVDS_A3_POWER_MASK) == LVDS_A3_POWER_UP) temp |= PIPE_8BPC; else temp |= PIPE_6BPC; @@ -3811,8 +3733,7 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc, } } else temp |= PIPE_8BPC; - I915_WRITE(pipeconf_reg, temp); - I915_READ(pipeconf_reg); + I915_WRITE(PIPECONF(pipe), temp); switch (temp & PIPE_BPC_MASK) { case PIPE_8BPC: @@ -3857,33 +3778,27 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc, /* Always enable nonspread source */ temp &= ~DREF_NONSPREAD_SOURCE_MASK; temp |= DREF_NONSPREAD_SOURCE_ENABLE; - I915_WRITE(PCH_DREF_CONTROL, temp); - POSTING_READ(PCH_DREF_CONTROL); - temp &= ~DREF_SSC_SOURCE_MASK; temp |= DREF_SSC_SOURCE_ENABLE; I915_WRITE(PCH_DREF_CONTROL, temp); - POSTING_READ(PCH_DREF_CONTROL); + POSTING_READ(PCH_DREF_CONTROL); udelay(200); if (has_edp_encoder) { if (dev_priv->lvds_use_ssc) { temp |= DREF_SSC1_ENABLE; I915_WRITE(PCH_DREF_CONTROL, temp); - POSTING_READ(PCH_DREF_CONTROL); + POSTING_READ(PCH_DREF_CONTROL); udelay(200); temp &= ~DREF_CPU_SOURCE_OUTPUT_MASK; temp |= DREF_CPU_SOURCE_OUTPUT_DOWNSPREAD; - I915_WRITE(PCH_DREF_CONTROL, temp); - POSTING_READ(PCH_DREF_CONTROL); } else { temp |= DREF_CPU_SOURCE_OUTPUT_NONSPREAD; - I915_WRITE(PCH_DREF_CONTROL, temp); - POSTING_READ(PCH_DREF_CONTROL); } + I915_WRITE(PCH_DREF_CONTROL, temp); } } @@ -3899,6 +3814,7 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc, reduced_clock.m2; } + dpll = 0; if (!HAS_PCH_SPLIT(dev)) dpll = DPLL_VGA_MODE_DIS; @@ -3972,7 +3888,7 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc, dpll |= PLL_REF_INPUT_DREFCLK; /* setup pipeconf */ - pipeconf = I915_READ(pipeconf_reg); + pipeconf = I915_READ(PIPECONF(pipe)); /* Set up the display plane register */ dspcntr = DISPPLANE_GAMMA_ENABLE; @@ -3995,16 +3911,15 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc, */ if (mode->clock > dev_priv->display.get_display_clock_speed(dev) * 9 / 10) - pipeconf |= PIPEACONF_DOUBLE_WIDE; + pipeconf |= PIPECONF_DOUBLE_WIDE; else - pipeconf &= ~PIPEACONF_DOUBLE_WIDE; + pipeconf &= ~PIPECONF_DOUBLE_WIDE; } dspcntr |= DISPLAY_PLANE_ENABLE; - pipeconf |= PIPEACONF_ENABLE; + pipeconf |= PIPECONF_ENABLE; dpll |= DPLL_VCO_ENABLE; - /* Disable the panel fitter if it was on our pipe */ if (!HAS_PCH_SPLIT(dev) && intel_panel_fitter_pipe(dev) == pipe) I915_WRITE(PFIT_CONTROL, 0); @@ -4014,26 +3929,31 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc, /* assign to Ironlake registers */ if (HAS_PCH_SPLIT(dev)) { - fp_reg = pch_fp_reg; - dpll_reg = pch_dpll_reg; + fp_reg = PCH_FP0(pipe); + dpll_reg = PCH_DPLL(pipe); + } else { + fp_reg = FP0(pipe); + dpll_reg = DPLL(pipe); } if (!has_edp_encoder) { I915_WRITE(fp_reg, fp); I915_WRITE(dpll_reg, dpll & ~DPLL_VCO_ENABLE); - I915_READ(dpll_reg); + + POSTING_READ(dpll_reg); udelay(150); } /* enable transcoder DPLL */ if (HAS_PCH_CPT(dev)) { temp = I915_READ(PCH_DPLL_SEL); - if (trans_dpll_sel == 0) - temp |= (TRANSA_DPLL_ENABLE | TRANSA_DPLLA_SEL); + if (pipe == 0) + temp |= TRANSA_DPLL_ENABLE | TRANSA_DPLLA_SEL; else - temp |= (TRANSB_DPLL_ENABLE | TRANSB_DPLLB_SEL); + temp |= TRANSB_DPLL_ENABLE | TRANSB_DPLLB_SEL; I915_WRITE(PCH_DPLL_SEL, temp); - I915_READ(PCH_DPLL_SEL); + + POSTING_READ(PCH_DPLL_SEL); udelay(150); } @@ -4042,33 +3962,32 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc, * things on. */ if (is_lvds) { - u32 lvds; - + reg = LVDS; if (HAS_PCH_SPLIT(dev)) - lvds_reg = PCH_LVDS; + reg = PCH_LVDS; - lvds = I915_READ(lvds_reg); - lvds |= LVDS_PORT_EN | LVDS_A0A2_CLKA_POWER_UP; + temp = I915_READ(reg); + temp |= LVDS_PORT_EN | LVDS_A0A2_CLKA_POWER_UP; if (pipe == 1) { if (HAS_PCH_CPT(dev)) - lvds |= PORT_TRANS_B_SEL_CPT; + temp |= PORT_TRANS_B_SEL_CPT; else - lvds |= LVDS_PIPEB_SELECT; + temp |= LVDS_PIPEB_SELECT; } else { if (HAS_PCH_CPT(dev)) - lvds &= ~PORT_TRANS_SEL_MASK; + temp &= ~PORT_TRANS_SEL_MASK; else - lvds &= ~LVDS_PIPEB_SELECT; + temp &= ~LVDS_PIPEB_SELECT; } /* set the corresponsding LVDS_BORDER bit */ - lvds |= dev_priv->lvds_border_bits; + temp |= dev_priv->lvds_border_bits; /* Set the B0-B3 data pairs corresponding to whether we're going to * set the DPLLs for dual-channel mode or not. */ if (clock.p2 == 7) - lvds |= LVDS_B0B3_POWER_UP | LVDS_CLKB_POWER_UP; + temp |= LVDS_B0B3_POWER_UP | LVDS_CLKB_POWER_UP; else - lvds &= ~(LVDS_B0B3_POWER_UP | LVDS_CLKB_POWER_UP); + temp &= ~(LVDS_B0B3_POWER_UP | LVDS_CLKB_POWER_UP); /* It would be nice to set 24 vs 18-bit mode (LVDS_A3_POWER_UP) * appropriately here, but we need to look more thoroughly into how @@ -4077,12 +3996,11 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc, /* set the dithering flag on non-PCH LVDS as needed */ if (IS_I965G(dev) && !HAS_PCH_SPLIT(dev)) { if (dev_priv->lvds_dither) - lvds |= LVDS_ENABLE_DITHER; + temp |= LVDS_ENABLE_DITHER; else - lvds &= ~LVDS_ENABLE_DITHER; + temp &= ~LVDS_ENABLE_DITHER; } - I915_WRITE(lvds_reg, lvds); - I915_READ(lvds_reg); + I915_WRITE(reg, temp); } /* set the dithering flag and clear for anything other than a panel. */ @@ -4115,32 +4033,32 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc, if (!has_edp_encoder) { I915_WRITE(fp_reg, fp); I915_WRITE(dpll_reg, dpll); - I915_READ(dpll_reg); + /* Wait for the clocks to stabilize. */ + POSTING_READ(dpll_reg); udelay(150); if (IS_I965G(dev) && !HAS_PCH_SPLIT(dev)) { + temp = 0; if (is_sdvo) { - int pixel_multiplier = intel_mode_get_pixel_multiplier(adjusted_mode); - if (pixel_multiplier > 1) - pixel_multiplier = (pixel_multiplier - 1) << DPLL_MD_UDI_MULTIPLIER_SHIFT; + temp = intel_mode_get_pixel_multiplier(adjusted_mode); + if (temp > 1) + temp = (temp - 1) << DPLL_MD_UDI_MULTIPLIER_SHIFT; else - pixel_multiplier = 0; - - I915_WRITE(dpll_md_reg, - (0 << DPLL_MD_UDI_DIVIDER_SHIFT) | - pixel_multiplier); - } else - I915_WRITE(dpll_md_reg, 0); + temp = 0; + } + I915_WRITE(DPLL_MD(pipe), temp); } else { /* write it again -- the BIOS does, after all */ I915_WRITE(dpll_reg, dpll); } - I915_READ(dpll_reg); + /* Wait for the clocks to stabilize. */ + POSTING_READ(dpll_reg); udelay(150); } + intel_crtc->lowfreq_avail = false; if (is_lvds && has_reduced_clock && i915_powersave) { I915_WRITE(fp_reg + 4, fp2); intel_crtc->lowfreq_avail = true; @@ -4150,7 +4068,6 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc, } } else { I915_WRITE(fp_reg + 4, fp); - intel_crtc->lowfreq_avail = false; if (HAS_PIPE_CXSR(dev)) { DRM_DEBUG_KMS("disabling CxSR downclocking\n"); pipeconf &= ~PIPECONF_CXSR_DOWNCLOCK; @@ -4169,58 +4086,72 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc, } else pipeconf &= ~PIPECONF_INTERLACE_W_FIELD_INDICATION; /* progressive */ - I915_WRITE(htot_reg, (adjusted_mode->crtc_hdisplay - 1) | + I915_WRITE(HTOTAL(pipe), + (adjusted_mode->crtc_hdisplay - 1) | ((adjusted_mode->crtc_htotal - 1) << 16)); - I915_WRITE(hblank_reg, (adjusted_mode->crtc_hblank_start - 1) | + I915_WRITE(HBLANK(pipe), + (adjusted_mode->crtc_hblank_start - 1) | ((adjusted_mode->crtc_hblank_end - 1) << 16)); - I915_WRITE(hsync_reg, (adjusted_mode->crtc_hsync_start - 1) | + I915_WRITE(HSYNC(pipe), + (adjusted_mode->crtc_hsync_start - 1) | ((adjusted_mode->crtc_hsync_end - 1) << 16)); - I915_WRITE(vtot_reg, (adjusted_mode->crtc_vdisplay - 1) | + + I915_WRITE(VTOTAL(pipe), + (adjusted_mode->crtc_vdisplay - 1) | ((adjusted_mode->crtc_vtotal - 1) << 16)); - I915_WRITE(vblank_reg, (adjusted_mode->crtc_vblank_start - 1) | + I915_WRITE(VBLANK(pipe), + (adjusted_mode->crtc_vblank_start - 1) | ((adjusted_mode->crtc_vblank_end - 1) << 16)); - I915_WRITE(vsync_reg, (adjusted_mode->crtc_vsync_start - 1) | + I915_WRITE(VSYNC(pipe), + (adjusted_mode->crtc_vsync_start - 1) | ((adjusted_mode->crtc_vsync_end - 1) << 16)); - /* pipesrc and dspsize control the size that is scaled from, which should - * always be the user's requested size. + + /* pipesrc and dspsize control the size that is scaled from, + * which should always be the user's requested size. */ if (!HAS_PCH_SPLIT(dev)) { - I915_WRITE(dspsize_reg, ((mode->vdisplay - 1) << 16) | - (mode->hdisplay - 1)); - I915_WRITE(dsppos_reg, 0); + I915_WRITE(DSPSIZE(plane), + ((mode->vdisplay - 1) << 16) | + (mode->hdisplay - 1)); + I915_WRITE(DSPPOS(plane), 0); } - I915_WRITE(pipesrc_reg, ((mode->hdisplay - 1) << 16) | (mode->vdisplay - 1)); + I915_WRITE(PIPESRC(pipe), + ((mode->hdisplay - 1) << 16) | (mode->vdisplay - 1)); if (HAS_PCH_SPLIT(dev)) { - I915_WRITE(data_m1_reg, TU_SIZE(m_n.tu) | m_n.gmch_m); - I915_WRITE(data_n1_reg, m_n.gmch_n); - I915_WRITE(link_m1_reg, m_n.link_m); - I915_WRITE(link_n1_reg, m_n.link_n); + I915_WRITE(PIPE_DATA_M1(pipe), TU_SIZE(m_n.tu) | m_n.gmch_m); + I915_WRITE(PIPE_DATA_N1(pipe), m_n.gmch_n); + I915_WRITE(PIPE_LINK_M1(pipe), m_n.link_m); + I915_WRITE(PIPE_LINK_N1(pipe), m_n.link_n); if (has_edp_encoder) { ironlake_set_pll_edp(crtc, adjusted_mode->clock); } else { /* enable FDI RX PLL too */ - temp = I915_READ(fdi_rx_reg); - I915_WRITE(fdi_rx_reg, temp | FDI_RX_PLL_ENABLE); - I915_READ(fdi_rx_reg); + reg = FDI_RX_CTL(pipe); + temp = I915_READ(reg); + I915_WRITE(reg, temp | FDI_RX_PLL_ENABLE); + + POSTING_READ(reg); udelay(200); /* enable FDI TX PLL too */ - temp = I915_READ(fdi_tx_reg); - I915_WRITE(fdi_tx_reg, temp | FDI_TX_PLL_ENABLE); - I915_READ(fdi_tx_reg); + reg = FDI_TX_CTL(pipe); + temp = I915_READ(reg); + I915_WRITE(reg, temp | FDI_TX_PLL_ENABLE); /* enable FDI RX PCDCLK */ - temp = I915_READ(fdi_rx_reg); - I915_WRITE(fdi_rx_reg, temp | FDI_SEL_PCDCLK); - I915_READ(fdi_rx_reg); + reg = FDI_RX_CTL(pipe); + temp = I915_READ(reg); + I915_WRITE(reg, temp | FDI_PCDCLK); + + POSTING_READ(reg); udelay(200); } } - I915_WRITE(pipeconf_reg, pipeconf); - I915_READ(pipeconf_reg); + I915_WRITE(PIPECONF(pipe), pipeconf); + POSTING_READ(PIPECONF(pipe)); intel_wait_for_vblank(dev, pipe); @@ -4230,9 +4161,8 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc, I915_WRITE(DISP_ARB_CTL, temp | DISP_TILE_SURFACE_SWIZZLING); } - I915_WRITE(dspcntr_reg, dspcntr); + I915_WRITE(DSPCNTR(plane), dspcntr); - /* Flush the plane changes */ ret = intel_pipe_set_base(crtc, x, y, old_fb); intel_update_watermarks(dev); diff --git a/drivers/gpu/drm/i915/intel_overlay.c b/drivers/gpu/drm/i915/intel_overlay.c index 743ced7..9dcddfc 100644 --- a/drivers/gpu/drm/i915/intel_overlay.c +++ b/drivers/gpu/drm/i915/intel_overlay.c @@ -255,7 +255,7 @@ i830_activate_pipe_a(struct drm_device *dev) return 0; /* most i8xx have pipe a forced on, so don't trust dpms mode */ - if (I915_READ(PIPEACONF) & PIPEACONF_ENABLE) + if (I915_READ(PIPEACONF) & PIPECONF_ENABLE) return 0; crtc_funcs = crtc->base.helper_private; @@ -876,15 +876,14 @@ static int check_overlay_possible_on_crtc(struct intel_overlay *overlay, { drm_i915_private_t *dev_priv = overlay->dev->dev_private; u32 pipeconf; - int pipeconf_reg = (crtc->pipe == 0) ? PIPEACONF : PIPEBCONF; if (!crtc->base.enabled || crtc->dpms_mode != DRM_MODE_DPMS_ON) return -EINVAL; - pipeconf = I915_READ(pipeconf_reg); + pipeconf = I915_READ(PIPECONF(crtc->pipe)); /* can't use the overlay with double wide pipe */ - if (!IS_I965G(overlay->dev) && pipeconf & PIPEACONF_DOUBLE_WIDE) + if (!IS_I965G(overlay->dev) && pipeconf & PIPECONF_DOUBLE_WIDE) return -EINVAL; return 0; diff --git a/drivers/gpu/drm/i915/intel_tv.c b/drivers/gpu/drm/i915/intel_tv.c index 267da32..e819cad 100644 --- a/drivers/gpu/drm/i915/intel_tv.c +++ b/drivers/gpu/drm/i915/intel_tv.c @@ -1168,7 +1168,7 @@ intel_tv_mode_set(struct drm_encoder *encoder, struct drm_display_mode *mode, if (!IS_I9XX(dev)) intel_wait_for_vblank(dev, intel_crtc->pipe); - I915_WRITE(pipeconf_reg, pipeconf & ~PIPEACONF_ENABLE); + I915_WRITE(pipeconf_reg, pipeconf & ~PIPECONF_ENABLE); /* Wait for vblank for the disable to take effect. */ intel_wait_for_vblank_off(dev, intel_crtc->pipe); -- cgit v1.1 From fe255d0028903f1132a3c1214edc91cf95b7cd98 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Sat, 11 Sep 2010 21:37:48 +0100 Subject: drm/i915/dp: Convert a udelay(17000) to a sleep during link-off Signed-off-by: Chris Wilson --- drivers/gpu/drm/i915/intel_dp.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c index 103a60b..208a4ec 100644 --- a/drivers/gpu/drm/i915/intel_dp.c +++ b/drivers/gpu/drm/i915/intel_dp.c @@ -1366,14 +1366,13 @@ intel_dp_link_down(struct intel_dp *intel_dp) if (HAS_PCH_CPT(dev) && !IS_eDP(intel_dp)) { DP &= ~DP_LINK_TRAIN_MASK_CPT; I915_WRITE(intel_dp->output_reg, DP | DP_LINK_TRAIN_PAT_IDLE_CPT); - POSTING_READ(intel_dp->output_reg); } else { DP &= ~DP_LINK_TRAIN_MASK; I915_WRITE(intel_dp->output_reg, DP | DP_LINK_TRAIN_PAT_IDLE); - POSTING_READ(intel_dp->output_reg); } + POSTING_READ(intel_dp->output_reg); - udelay(17000); + msleep(17); if (IS_eDP(intel_dp)) DP |= DP_LINK_TRAIN_OFF; -- cgit v1.1 From b222f2673354c65e178cbcba610e7883a05f5bf3 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Sat, 11 Sep 2010 21:48:25 +0100 Subject: drm/i915/i2c: The bit-banging interface controls the delay, drop ours Remove our redundant udelay() as the timings are already handled by the i2c-algo-bit controller. Signed-off-by: Chris Wilson --- drivers/gpu/drm/i915/intel_i2c.c | 34 +++++++++++++++------------------- 1 file changed, 15 insertions(+), 19 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_i2c.c b/drivers/gpu/drm/i915/intel_i2c.c index c2649c7..de03989 100644 --- a/drivers/gpu/drm/i915/intel_i2c.c +++ b/drivers/gpu/drm/i915/intel_i2c.c @@ -38,16 +38,18 @@ void intel_i2c_quirk_set(struct drm_device *dev, bool enable) { struct drm_i915_private *dev_priv = dev->dev_private; + u32 val; /* When using bit bashing for I2C, this bit needs to be set to 1 */ if (!IS_PINEVIEW(dev)) return; + + val = I915_READ(DSPCLK_GATE_D); if (enable) - I915_WRITE(DSPCLK_GATE_D, - I915_READ(DSPCLK_GATE_D) | DPCUNIT_CLOCK_GATE_DISABLE); + val |= DPCUNIT_CLOCK_GATE_DISABLE; else - I915_WRITE(DSPCLK_GATE_D, - I915_READ(DSPCLK_GATE_D) & (~DPCUNIT_CLOCK_GATE_DISABLE)); + val &= ~DPCUNIT_CLOCK_GATE_DISABLE; + I915_WRITE(DSPCLK_GATE_D, val); } /* @@ -60,20 +62,14 @@ static int get_clock(void *data) { struct intel_i2c_chan *chan = data; struct drm_i915_private *dev_priv = chan->drm_dev->dev_private; - u32 val; - - val = I915_READ(chan->reg); - return ((val & GPIO_CLOCK_VAL_IN) != 0); + return (I915_READ(chan->reg) & GPIO_CLOCK_VAL_IN) != 0; } static int get_data(void *data) { struct intel_i2c_chan *chan = data; struct drm_i915_private *dev_priv = chan->drm_dev->dev_private; - u32 val; - - val = I915_READ(chan->reg); - return ((val & GPIO_DATA_VAL_IN) != 0); + return (I915_READ(chan->reg) & GPIO_DATA_VAL_IN) != 0; } static void set_clock(void *data, int state_high) @@ -94,7 +90,7 @@ static void set_clock(void *data, int state_high) clock_bits = GPIO_CLOCK_DIR_OUT | GPIO_CLOCK_DIR_MASK | GPIO_CLOCK_VAL_MASK; I915_WRITE(chan->reg, reserved | clock_bits); - udelay(I2C_RISEFALL_TIME); /* wait for the line to change state */ + POSTING_READ(chan->reg); } static void set_data(void *data, int state_high) @@ -116,7 +112,7 @@ static void set_data(void *data, int state_high) GPIO_DATA_VAL_MASK; I915_WRITE(chan->reg, reserved | data_bits); - udelay(I2C_RISEFALL_TIME); /* wait for the line to change state */ + POSTING_READ(chan->reg); } /* Clears the GMBUS setup. Our driver doesn't make use of the GMBUS I2C @@ -129,11 +125,10 @@ intel_i2c_reset_gmbus(struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; - if (HAS_PCH_SPLIT(dev)) { + if (HAS_PCH_SPLIT(dev)) I915_WRITE(PCH_GMBUS0, 0); - } else { + else I915_WRITE(GMBUS0, 0); - } } /** @@ -177,7 +172,7 @@ struct i2c_adapter *intel_i2c_create(struct drm_device *dev, const u32 reg, chan->algo.setscl = set_clock; chan->algo.getsda = get_data; chan->algo.getscl = get_clock; - chan->algo.udelay = 20; + chan->algo.udelay = I2C_RISEFALL_TIME; chan->algo.timeout = usecs_to_jiffies(2200); chan->algo.data = chan; @@ -191,9 +186,10 @@ struct i2c_adapter *intel_i2c_create(struct drm_device *dev, const u32 reg, /* JJJ: raise SCL and SDA? */ intel_i2c_quirk_set(dev, true); set_data(chan, 1); + udelay(I2C_RISEFALL_TIME); set_clock(chan, 1); + udelay(I2C_RISEFALL_TIME); intel_i2c_quirk_set(dev, false); - udelay(20); return &chan->adapter; -- cgit v1.1 From 77d07fd9d73ef28689737c0952dbd5d6a5017743 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Sun, 12 Sep 2010 12:42:35 +0100 Subject: drm/i915/lvds: Remove busy wait for powering down the panel Just assume that it will turn off... Reported-by: Sitsofe Wheeler Signed-off-by: Chris Wilson --- drivers/gpu/drm/i915/intel_lvds.c | 11 ++--------- 1 file changed, 2 insertions(+), 9 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_lvds.c b/drivers/gpu/drm/i915/intel_lvds.c index 93a711d..f533169 100644 --- a/drivers/gpu/drm/i915/intel_lvds.c +++ b/drivers/gpu/drm/i915/intel_lvds.c @@ -83,10 +83,7 @@ static void intel_lvds_set_power(struct drm_device *dev, bool on) if (on) { I915_WRITE(lvds_reg, I915_READ(lvds_reg) | LVDS_PORT_EN); - POSTING_READ(lvds_reg); - - I915_WRITE(ctl_reg, I915_READ(ctl_reg) | - POWER_TARGET_ON); + I915_WRITE(ctl_reg, I915_READ(ctl_reg) | POWER_TARGET_ON); if (wait_for(I915_READ(status_reg) & PP_ON, 1000)) DRM_ERROR("timed out waiting to enable LVDS pipe"); @@ -94,11 +91,7 @@ static void intel_lvds_set_power(struct drm_device *dev, bool on) } else { intel_panel_set_backlight(dev, 0); - I915_WRITE(ctl_reg, I915_READ(ctl_reg) & - ~POWER_TARGET_ON); - if (wait_for((I915_READ(status_reg) & PP_ON) == 0, 1000)) - DRM_ERROR("timed out waiting for LVDS pipe to turn off"); - + I915_WRITE(ctl_reg, I915_READ(ctl_reg) & ~POWER_TARGET_ON); I915_WRITE(lvds_reg, I915_READ(lvds_reg) & ~LVDS_PORT_EN); POSTING_READ(lvds_reg); } -- cgit v1.1 From c9f9ccc150e119bab6a1003e7762b024623011d8 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Sun, 12 Sep 2010 13:07:25 +0100 Subject: drm/i915/lvds: Remove busy wait for powering up the panel. We just assume that it will happen in a timely manner. A variant of this patch was first written and tested by Arjan van de Van. Signed-off-by: Chris Wilson --- drivers/gpu/drm/i915/intel_lvds.c | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_lvds.c b/drivers/gpu/drm/i915/intel_lvds.c index f533169..9089604 100644 --- a/drivers/gpu/drm/i915/intel_lvds.c +++ b/drivers/gpu/drm/i915/intel_lvds.c @@ -84,17 +84,13 @@ static void intel_lvds_set_power(struct drm_device *dev, bool on) if (on) { I915_WRITE(lvds_reg, I915_READ(lvds_reg) | LVDS_PORT_EN); I915_WRITE(ctl_reg, I915_READ(ctl_reg) | POWER_TARGET_ON); - if (wait_for(I915_READ(status_reg) & PP_ON, 1000)) - DRM_ERROR("timed out waiting to enable LVDS pipe"); - intel_panel_set_backlight(dev, dev_priv->backlight_level); } else { intel_panel_set_backlight(dev, 0); - I915_WRITE(ctl_reg, I915_READ(ctl_reg) & ~POWER_TARGET_ON); I915_WRITE(lvds_reg, I915_READ(lvds_reg) & ~LVDS_PORT_EN); - POSTING_READ(lvds_reg); } + POSTING_READ(lvds_reg); } static void intel_lvds_dpms(struct drm_encoder *encoder, int mode) -- cgit v1.1 From ec5da01e23eec303dd313aa62b8ed4712c488437 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Sun, 12 Sep 2010 13:34:08 +0100 Subject: drm/i915: Use msleep instead of mdelay during wait_vblank_off Avoid a potentially long busy-wait if we not in the process of atomically switching to the kdb console. Signed-off-by: Chris Wilson --- drivers/gpu/drm/i915/intel_display.c | 13 +++++++------ drivers/gpu/drm/i915/intel_drv.h | 7 +++++++ 2 files changed, 14 insertions(+), 6 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 1e88ebb..594f8f2 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -1034,16 +1034,17 @@ void intel_wait_for_vblank_off(struct drm_device *dev, int pipe) struct drm_i915_private *dev_priv = dev->dev_private; int pipedsl_reg = (pipe == 0 ? PIPEADSL : PIPEBDSL); unsigned long timeout = jiffies + msecs_to_jiffies(100); - u32 last_line; + u32 last_line, line; /* Wait for the display line to settle */ + line = I915_READ(pipedsl_reg) & DSL_LINEMASK; do { - last_line = I915_READ(pipedsl_reg) & DSL_LINEMASK; - mdelay(5); - } while (((I915_READ(pipedsl_reg) & DSL_LINEMASK) != last_line) && - time_after(timeout, jiffies)); + last_line = line; + MSLEEP(5); + line = I915_READ(pipedsl_reg) & DSL_LINEMASK; + } while (line != last_line && time_after(timeout, jiffies)); - if (time_after(jiffies, timeout)) + if (line != last_line) DRM_DEBUG_KMS("vblank wait timed out\n"); } diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index 6c6b897..e5f2a61 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -49,6 +49,13 @@ #define wait_for(COND, MS) _wait_for(COND, MS, 1) #define wait_for_atomic(COND, MS) _wait_for(COND, MS, 0) +#define MSLEEP(x) do { \ + if (in_dbg_master()) \ + mdelay(x); \ + else \ + msleep(x); \ +} while(0) + #define KHz(x) (1000*x) #define MHz(x) KHz(1000*x) -- cgit v1.1 From b5c616a75428d85f92407e4509553f937b720630 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Thu, 9 Sep 2010 19:06:13 +0100 Subject: drm/i915/sdvo: Poll command status 5 times without delay on read The documentation says that an SDVO command takes a maximum of 15us to be processed by the device, and that it is sufficient to read the status byte 3 times (whilst the command is still in the PENDING state) for the driver to be confident that sufficient time has elapsed. We err on the safe side and try 5 times before giving up. The only question that remains: was the old behaviour derived by experiments with real hardware? A look into the murky history of UMS, implies that the behaviour was accidental and the current retry mechanism was solely designed to catch the status byte indicating PENDING with no reference to hardware behaviour. (commit ac9181c014638dbeb334b40b4029d0ccb2b7a0fc in xf86-video-intel) Signed-off-by: Chris Wilson --- drivers/gpu/drm/i915/intel_sdvo.c | 71 ++++++++++++++++++++------------------- 1 file changed, 36 insertions(+), 35 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_sdvo.c b/drivers/gpu/drm/i915/intel_sdvo.c index 96952d2..a812d65 100644 --- a/drivers/gpu/drm/i915/intel_sdvo.c +++ b/drivers/gpu/drm/i915/intel_sdvo.c @@ -462,54 +462,55 @@ static const char *cmd_status_names[] = { "Scaling not supported" }; -static void intel_sdvo_debug_response(struct intel_sdvo *intel_sdvo, - void *response, int response_len, - u8 status) +static bool intel_sdvo_read_response(struct intel_sdvo *intel_sdvo, + void *response, int response_len) { + u8 retry = 5; + u8 status; int i; + /* + * The documentation states that all commands will be + * processed within 15µs, and that we need only poll + * the status byte a maximum of 3 times in order for the + * command to be complete. + * + * Check 5 times in case the hardware failed to read the docs. + */ + do { + if (!intel_sdvo_read_byte(intel_sdvo, + SDVO_I2C_CMD_STATUS, + &status)) + return false; + } while (status == SDVO_CMD_STATUS_PENDING && --retry); + DRM_DEBUG_KMS("%s: R: ", SDVO_NAME(intel_sdvo)); - for (i = 0; i < response_len; i++) - DRM_LOG_KMS("%02X ", ((u8 *)response)[i]); - for (; i < 8; i++) - DRM_LOG_KMS(" "); if (status <= SDVO_CMD_STATUS_SCALING_NOT_SUPP) DRM_LOG_KMS("(%s)", cmd_status_names[status]); else DRM_LOG_KMS("(??? %d)", status); - DRM_LOG_KMS("\n"); -} -static bool intel_sdvo_read_response(struct intel_sdvo *intel_sdvo, - void *response, int response_len) -{ - int i; - u8 status; - u8 retry = 50; - - while (retry--) { - /* Read the command response */ - for (i = 0; i < response_len; i++) { - if (!intel_sdvo_read_byte(intel_sdvo, - SDVO_I2C_RETURN_0 + i, - &((u8 *)response)[i])) - return false; - } + if (status != SDVO_CMD_STATUS_SUCCESS) + goto log_fail; - /* read the return status */ - if (!intel_sdvo_read_byte(intel_sdvo, SDVO_I2C_CMD_STATUS, - &status)) - return false; + /* Read the command response */ + for (i = 0; i < response_len; i++) { + if (!intel_sdvo_read_byte(intel_sdvo, + SDVO_I2C_RETURN_0 + i, + &((u8 *)response)[i])) + goto log_fail; + DRM_LOG_KMS("%02X ", ((u8 *)response)[i]); + } - intel_sdvo_debug_response(intel_sdvo, response, response_len, - status); - if (status != SDVO_CMD_STATUS_PENDING) - break; + for (; i < 8; i++) + DRM_LOG_KMS(" "); + DRM_LOG_KMS("\n"); - mdelay(50); - } + return true; - return status == SDVO_CMD_STATUS_SUCCESS; +log_fail: + DRM_LOG_KMS("\n"); + return false; } static int intel_sdvo_get_pixel_multiplier(struct drm_display_mode *mode) -- cgit v1.1 From 6edc3242e35f03990e362e7c115e722717f0f7a7 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Sun, 12 Sep 2010 17:16:17 +0100 Subject: drm/i915/bios: Prevent NULL dereference after allocation failure Signed-off-by: Chris Wilson --- drivers/gpu/drm/i915/intel_bios.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/gpu/drm/i915/intel_bios.c b/drivers/gpu/drm/i915/intel_bios.c index 8d7deca..8986a4b 100644 --- a/drivers/gpu/drm/i915/intel_bios.c +++ b/drivers/gpu/drm/i915/intel_bios.c @@ -169,6 +169,8 @@ parse_lfp_panel_data(struct drm_i915_private *dev_priv, ((unsigned char *)entry + dvo_timing_offset); panel_fixed_mode = kzalloc(sizeof(*panel_fixed_mode), GFP_KERNEL); + if (!panel_fixed_mode) + return; fill_detail_timing_data(panel_fixed_mode, dvo_timing); -- cgit v1.1 From e9e331a8abeece1565d383510ed985945132ffe3 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Mon, 13 Sep 2010 01:16:10 +0100 Subject: drm/i915/lvds: Ensure panel is unlocked for Ironlake or the panel fitter Commit 77d07fd9d73ef28689737c0952dbd5d6a5017743 introduced a regression where by not waiting for the panel to be turned off, left the panel and PLL registers locked across the modeset. Thus the panel remaining blank. As pointed out by Daniel Vetter, when testing LVDS it helps to open the laptop and look at the actual panel you are purporting to test. A second issue with the patch was that in order to modify the panel fitter before gen5, the pipe and the panel must have be completely powered down. So we wait. Signed-off-by: Chris Wilson --- drivers/gpu/drm/i915/intel_display.c | 31 ----------- drivers/gpu/drm/i915/intel_drv.h | 1 - drivers/gpu/drm/i915/intel_lvds.c | 103 +++++++++++++++++++++++++---------- drivers/gpu/drm/i915/intel_overlay.c | 33 ++++++++++- 4 files changed, 105 insertions(+), 63 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 594f8f2..0004534 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -2636,33 +2636,6 @@ static int i830_get_display_clock_speed(struct drm_device *dev) return 133000; } -/** - * Return the pipe currently connected to the panel fitter, - * or -1 if the panel fitter is not present or not in use - */ -int intel_panel_fitter_pipe (struct drm_device *dev) -{ - struct drm_i915_private *dev_priv = dev->dev_private; - u32 pfit_control; - - /* i830 doesn't have a panel fitter */ - if (IS_I830(dev)) - return -1; - - pfit_control = I915_READ(PFIT_CONTROL); - - /* See if the panel fitter is in use */ - if ((pfit_control & PFIT_ENABLE) == 0) - return -1; - - /* 965 can place panel fitter on either pipe */ - if (IS_I965G(dev)) - return (pfit_control >> 29) & 0x3; - - /* older chips can only use pipe 1 */ - return 1; -} - struct fdi_m_n { u32 tu; u32 gmch_m; @@ -3921,10 +3894,6 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc, pipeconf |= PIPECONF_ENABLE; dpll |= DPLL_VCO_ENABLE; - /* Disable the panel fitter if it was on our pipe */ - if (!HAS_PCH_SPLIT(dev) && intel_panel_fitter_pipe(dev) == pipe) - I915_WRITE(PFIT_CONTROL, 0); - DRM_DEBUG_KMS("Mode for pipe %c:\n", pipe == 0 ? 'A' : 'B'); drm_mode_debug_printmodeline(mode); diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index e5f2a61..7e2646f 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -239,7 +239,6 @@ extern u32 intel_panel_get_max_backlight(struct drm_device *dev); extern u32 intel_panel_get_backlight(struct drm_device *dev); extern void intel_panel_set_backlight(struct drm_device *dev, u32 level); -extern int intel_panel_fitter_pipe (struct drm_device *dev); extern void intel_crtc_load_lut(struct drm_crtc *crtc); extern void intel_encoder_prepare (struct drm_encoder *encoder); extern void intel_encoder_commit (struct drm_encoder *encoder); diff --git a/drivers/gpu/drm/i915/intel_lvds.c b/drivers/gpu/drm/i915/intel_lvds.c index 9089604..bfc1bb4 100644 --- a/drivers/gpu/drm/i915/intel_lvds.c +++ b/drivers/gpu/drm/i915/intel_lvds.c @@ -46,6 +46,7 @@ struct intel_lvds { int fitting_mode; u32 pfit_control; u32 pfit_pgm_ratios; + bool pfit_dirty; }; static struct intel_lvds *enc_to_intel_lvds(struct drm_encoder *encoder) @@ -53,31 +54,20 @@ static struct intel_lvds *enc_to_intel_lvds(struct drm_encoder *encoder) return container_of(encoder, struct intel_lvds, base.base); } -static void intel_lvds_lock_panel(struct drm_device *dev, bool lock) -{ - struct drm_i915_private *dev_priv = dev->dev_private; - - if (lock) - I915_WRITE(PP_CONTROL, I915_READ(PP_CONTROL) & 0x3); - else - I915_WRITE(PP_CONTROL, I915_READ(PP_CONTROL) | PANEL_UNLOCK_REGS); -} - /** * Sets the power state for the panel. */ -static void intel_lvds_set_power(struct drm_device *dev, bool on) +static void intel_lvds_set_power(struct intel_lvds *intel_lvds, bool on) { + struct drm_device *dev = intel_lvds->base.base.dev; struct drm_i915_private *dev_priv = dev->dev_private; - u32 ctl_reg, status_reg, lvds_reg; + u32 ctl_reg, lvds_reg; if (HAS_PCH_SPLIT(dev)) { ctl_reg = PCH_PP_CONTROL; - status_reg = PCH_PP_STATUS; lvds_reg = PCH_LVDS; } else { ctl_reg = PP_CONTROL; - status_reg = PP_STATUS; lvds_reg = LVDS; } @@ -86,8 +76,18 @@ static void intel_lvds_set_power(struct drm_device *dev, bool on) I915_WRITE(ctl_reg, I915_READ(ctl_reg) | POWER_TARGET_ON); intel_panel_set_backlight(dev, dev_priv->backlight_level); } else { + dev_priv->backlight_level = intel_panel_get_backlight(dev); + intel_panel_set_backlight(dev, 0); I915_WRITE(ctl_reg, I915_READ(ctl_reg) & ~POWER_TARGET_ON); + + if (intel_lvds->pfit_control) { + if (wait_for((I915_READ(PP_STATUS) & PP_ON) == 0, 1000)) + DRM_ERROR("timed out waiting for panel to power off\n"); + I915_WRITE(PFIT_CONTROL, 0); + intel_lvds->pfit_control = 0; + } + I915_WRITE(lvds_reg, I915_READ(lvds_reg) & ~LVDS_PORT_EN); } POSTING_READ(lvds_reg); @@ -95,12 +95,12 @@ static void intel_lvds_set_power(struct drm_device *dev, bool on) static void intel_lvds_dpms(struct drm_encoder *encoder, int mode) { - struct drm_device *dev = encoder->dev; + struct intel_lvds *intel_lvds = enc_to_intel_lvds(encoder); if (mode == DRM_MODE_DPMS_ON) - intel_lvds_set_power(dev, true); + intel_lvds_set_power(intel_lvds, true); else - intel_lvds_set_power(dev, false); + intel_lvds_set_power(intel_lvds, false); /* XXX: We never power down the LVDS pairs. */ } @@ -331,8 +331,12 @@ static bool intel_lvds_mode_fixup(struct drm_encoder *encoder, } out: - intel_lvds->pfit_control = pfit_control; - intel_lvds->pfit_pgm_ratios = pfit_pgm_ratios; + if (pfit_control != intel_lvds->pfit_control || + pfit_pgm_ratios != intel_lvds->pfit_pgm_ratios) { + intel_lvds->pfit_control = pfit_control; + intel_lvds->pfit_pgm_ratios = pfit_pgm_ratios; + intel_lvds->pfit_dirty = true; + } dev_priv->lvds_border_bits = border; /* @@ -352,24 +356,56 @@ static void intel_lvds_prepare(struct drm_encoder *encoder) dev_priv->backlight_level = intel_panel_get_backlight(dev); - if (intel_lvds->pfit_control == I915_READ(PFIT_CONTROL)) - intel_lvds_lock_panel(dev, false); - else - intel_lvds_set_power(dev, false); + /* We try to do the minimum that is necessary in order to unlock + * the registers for mode setting. + * + * On Ironlake, this is quite simple as we just set the unlock key + * and ignore all subtleties. (This may cause some issues...) + * + * Prior to Ironlake, we must disable the pipe if we want to adjust + * the panel fitter. However at all other times we can just reset + * the registers regardless. + */ + + if (HAS_PCH_SPLIT(dev)) { + I915_WRITE(PCH_PP_CONTROL, + I915_READ(PCH_PP_CONTROL) | PANEL_UNLOCK_REGS); + } else if (intel_lvds->pfit_dirty) { + I915_WRITE(PP_CONTROL, + I915_READ(PP_CONTROL) & ~POWER_TARGET_ON); + I915_WRITE(LVDS, I915_READ(LVDS) & ~LVDS_PORT_EN); + } else { + I915_WRITE(PP_CONTROL, + I915_READ(PP_CONTROL) | PANEL_UNLOCK_REGS); + } } -static void intel_lvds_commit( struct drm_encoder *encoder) +static void intel_lvds_commit(struct drm_encoder *encoder) { struct drm_device *dev = encoder->dev; struct drm_i915_private *dev_priv = dev->dev_private; + struct intel_lvds *intel_lvds = enc_to_intel_lvds(encoder); if (dev_priv->backlight_level == 0) dev_priv->backlight_level = intel_panel_get_max_backlight(dev); - if ((I915_READ(PP_CONTROL) & PANEL_UNLOCK_REGS) == PANEL_UNLOCK_REGS) - intel_lvds_lock_panel(dev, true); - else - intel_lvds_set_power(dev, true); + /* Undo any unlocking done in prepare to prevent accidental + * adjustment of the registers. + */ + if (HAS_PCH_SPLIT(dev)) { + u32 val = I915_READ(PCH_PP_CONTROL); + if ((val & PANEL_UNLOCK_REGS) == PANEL_UNLOCK_REGS) + I915_WRITE(PCH_PP_CONTROL, val & 0x3); + } else { + u32 val = I915_READ(PP_CONTROL); + if ((val & PANEL_UNLOCK_REGS) == PANEL_UNLOCK_REGS) + I915_WRITE(PP_CONTROL, val & 0x3); + } + + /* Always do a full power on as we do not know what state + * we were left in. + */ + intel_lvds_set_power(intel_lvds, true); } static void intel_lvds_mode_set(struct drm_encoder *encoder, @@ -389,13 +425,20 @@ static void intel_lvds_mode_set(struct drm_encoder *encoder, if (HAS_PCH_SPLIT(dev)) return; + if (!intel_lvds->pfit_dirty) + return; + /* * Enable automatic panel scaling so that non-native modes fill the * screen. Should be enabled before the pipe is enabled, according to * register description and PRM. */ + if (wait_for((I915_READ(PP_STATUS) & PP_ON) == 0, 1000)) + DRM_ERROR("timed out waiting for panel to power off\n"); + I915_WRITE(PFIT_PGM_RATIOS, intel_lvds->pfit_pgm_ratios); I915_WRITE(PFIT_CONTROL, intel_lvds->pfit_control); + intel_lvds->pfit_dirty = false; } /** @@ -824,6 +867,10 @@ void intel_lvds_init(struct drm_device *dev) return; } + if (!HAS_PCH_SPLIT(dev)) { + intel_lvds->pfit_control = I915_READ(PFIT_CONTROL); + } + intel_encoder = &intel_lvds->base; encoder = &intel_encoder->base; connector = &intel_connector->base; diff --git a/drivers/gpu/drm/i915/intel_overlay.c b/drivers/gpu/drm/i915/intel_overlay.c index 9dcddfc..3dff161 100644 --- a/drivers/gpu/drm/i915/intel_overlay.c +++ b/drivers/gpu/drm/i915/intel_overlay.c @@ -1050,6 +1050,33 @@ static int check_overlay_src(struct drm_device *dev, return 0; } +/** + * Return the pipe currently connected to the panel fitter, + * or -1 if the panel fitter is not present or not in use + */ +static int intel_panel_fitter_pipe(struct drm_device *dev) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + u32 pfit_control; + + /* i830 doesn't have a panel fitter */ + if (IS_I830(dev)) + return -1; + + pfit_control = I915_READ(PFIT_CONTROL); + + /* See if the panel fitter is in use */ + if ((pfit_control & PFIT_ENABLE) == 0) + return -1; + + /* 965 can place panel fitter on either pipe */ + if (IS_I965G(dev)) + return (pfit_control >> 29) & 0x3; + + /* older chips can only use pipe 1 */ + return 1; +} + int intel_overlay_put_image(struct drm_device *dev, void *data, struct drm_file *file_priv) { @@ -1124,9 +1151,9 @@ int intel_overlay_put_image(struct drm_device *dev, void *data, overlay->crtc = crtc; crtc->overlay = overlay; - if (intel_panel_fitter_pipe(dev) == crtc->pipe - /* and line to wide, i.e. one-line-mode */ - && mode->hdisplay > 1024) { + /* line too wide, i.e. one-line-mode */ + if (mode->hdisplay > 1024 && + intel_panel_fitter_pipe(dev) == crtc->pipe) { overlay->pfit_active = 1; update_pfit_vscale_ratio(overlay); } else -- cgit v1.1 From 8aadf70bd72c8f15994e68503af8f6722cd5c813 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Sun, 12 Sep 2010 16:33:47 +0100 Subject: drm/i915/lvds: Remove incorrect mode locking One doesn't need to hold the mode lock in order to duplicate a mode. Signed-off-by: Chris Wilson --- drivers/gpu/drm/i915/intel_lvds.c | 7 ------- 1 file changed, 7 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_lvds.c b/drivers/gpu/drm/i915/intel_lvds.c index bfc1bb4..a05ca32 100644 --- a/drivers/gpu/drm/i915/intel_lvds.c +++ b/drivers/gpu/drm/i915/intel_lvds.c @@ -732,7 +732,6 @@ static void intel_find_lvds_downclock(struct drm_device *dev, panel_fixed_mode = dev_priv->panel_fixed_mode; temp_downclock = panel_fixed_mode->clock; - mutex_lock(&dev->mode_config.mutex); list_for_each_entry(scan, &connector->probed_modes, head) { /* * If one mode has the same resolution with the fixed_panel @@ -758,7 +757,6 @@ static void intel_find_lvds_downclock(struct drm_device *dev, } } } - mutex_unlock(&dev->mode_config.mutex); if (temp_downclock < panel_fixed_mode->clock && i915_lvds_downclock) { /* We found the downclock for LVDS. */ @@ -929,23 +927,18 @@ void intel_lvds_init(struct drm_device *dev) dev_priv->lvds_edid_good = false; list_for_each_entry(scan, &connector->probed_modes, head) { - mutex_lock(&dev->mode_config.mutex); if (scan->type & DRM_MODE_TYPE_PREFERRED) { dev_priv->panel_fixed_mode = drm_mode_duplicate(dev, scan); - mutex_unlock(&dev->mode_config.mutex); intel_find_lvds_downclock(dev, connector); goto out; } - mutex_unlock(&dev->mode_config.mutex); } /* Failed to get EDID, what about VBT? */ if (dev_priv->lfp_lvds_vbt_mode) { - mutex_lock(&dev->mode_config.mutex); dev_priv->panel_fixed_mode = drm_mode_duplicate(dev, dev_priv->lfp_lvds_vbt_mode); - mutex_unlock(&dev->mode_config.mutex); if (dev_priv->panel_fixed_mode) { dev_priv->panel_fixed_mode->type |= DRM_MODE_TYPE_PREFERRED; -- cgit v1.1 From 788319d48dc2b61db732b19bb9598c062c75ec37 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Sun, 12 Sep 2010 17:34:41 +0100 Subject: drm/i915/lvds: Move private data to the connector from the device. Signed-off-by: Chris Wilson --- drivers/gpu/drm/i915/i915_drv.h | 2 - drivers/gpu/drm/i915/intel_lvds.c | 155 +++++++++++++++++++------------------- 2 files changed, 78 insertions(+), 79 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index b3efb30..232555e 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -634,8 +634,6 @@ typedef struct drm_i915_private { /* Reclocking support */ bool render_reclock_avail; bool lvds_downclock_avail; - /* indicate whether the LVDS EDID is OK */ - bool lvds_edid_good; /* indicates the reduced downclock for LVDS*/ int lvds_downclock; struct work_struct idle_work; diff --git a/drivers/gpu/drm/i915/intel_lvds.c b/drivers/gpu/drm/i915/intel_lvds.c index a05ca32..b56b592 100644 --- a/drivers/gpu/drm/i915/intel_lvds.c +++ b/drivers/gpu/drm/i915/intel_lvds.c @@ -43,17 +43,28 @@ /* Private structure for the integrated LVDS support */ struct intel_lvds { struct intel_encoder base; + + bool edid_good; + int fitting_mode; u32 pfit_control; u32 pfit_pgm_ratios; bool pfit_dirty; + + struct drm_display_mode *fixed_mode; }; -static struct intel_lvds *enc_to_intel_lvds(struct drm_encoder *encoder) +static struct intel_lvds *to_intel_lvds(struct drm_encoder *encoder) { return container_of(encoder, struct intel_lvds, base.base); } +static struct intel_lvds *intel_attached_lvds(struct drm_connector *connector) +{ + return container_of(intel_attached_encoder(connector), + struct intel_lvds, base); +} + /** * Sets the power state for the panel. */ @@ -95,7 +106,7 @@ static void intel_lvds_set_power(struct intel_lvds *intel_lvds, bool on) static void intel_lvds_dpms(struct drm_encoder *encoder, int mode) { - struct intel_lvds *intel_lvds = enc_to_intel_lvds(encoder); + struct intel_lvds *intel_lvds = to_intel_lvds(encoder); if (mode == DRM_MODE_DPMS_ON) intel_lvds_set_power(intel_lvds, true); @@ -108,16 +119,13 @@ static void intel_lvds_dpms(struct drm_encoder *encoder, int mode) static int intel_lvds_mode_valid(struct drm_connector *connector, struct drm_display_mode *mode) { - struct drm_device *dev = connector->dev; - struct drm_i915_private *dev_priv = dev->dev_private; - struct drm_display_mode *fixed_mode = dev_priv->panel_fixed_mode; + struct intel_lvds *intel_lvds = intel_attached_lvds(connector); + struct drm_display_mode *fixed_mode = intel_lvds->fixed_mode; - if (fixed_mode) { - if (mode->hdisplay > fixed_mode->hdisplay) - return MODE_PANEL; - if (mode->vdisplay > fixed_mode->vdisplay) - return MODE_PANEL; - } + if (mode->hdisplay > fixed_mode->hdisplay) + return MODE_PANEL; + if (mode->vdisplay > fixed_mode->vdisplay) + return MODE_PANEL; return MODE_OK; } @@ -185,7 +193,7 @@ static bool intel_lvds_mode_fixup(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); - struct intel_lvds *intel_lvds = enc_to_intel_lvds(encoder); + struct intel_lvds *intel_lvds = to_intel_lvds(encoder); struct drm_encoder *tmp_encoder; u32 pfit_control = 0, pfit_pgm_ratios = 0, border = 0; @@ -203,9 +211,6 @@ static bool intel_lvds_mode_fixup(struct drm_encoder *encoder, return false; } } - /* If we don't have a panel mode, there is nothing we can do */ - if (dev_priv->panel_fixed_mode == NULL) - return true; /* * We have timings from the BIOS for the panel, put them in @@ -213,7 +218,7 @@ static bool intel_lvds_mode_fixup(struct drm_encoder *encoder, * with the panel scaling set up to source from the H/VDisplay * of the original mode. */ - intel_fixed_panel_mode(dev_priv->panel_fixed_mode, adjusted_mode); + intel_fixed_panel_mode(intel_lvds->fixed_mode, adjusted_mode); if (HAS_PCH_SPLIT(dev)) { intel_pch_panel_fitting(dev, intel_lvds->fitting_mode, @@ -352,7 +357,7 @@ static void intel_lvds_prepare(struct drm_encoder *encoder) { struct drm_device *dev = encoder->dev; struct drm_i915_private *dev_priv = dev->dev_private; - struct intel_lvds *intel_lvds = enc_to_intel_lvds(encoder); + struct intel_lvds *intel_lvds = to_intel_lvds(encoder); dev_priv->backlight_level = intel_panel_get_backlight(dev); @@ -384,7 +389,7 @@ static void intel_lvds_commit(struct drm_encoder *encoder) { struct drm_device *dev = encoder->dev; struct drm_i915_private *dev_priv = dev->dev_private; - struct intel_lvds *intel_lvds = enc_to_intel_lvds(encoder); + struct intel_lvds *intel_lvds = to_intel_lvds(encoder); if (dev_priv->backlight_level == 0) dev_priv->backlight_level = intel_panel_get_max_backlight(dev); @@ -414,7 +419,7 @@ static void intel_lvds_mode_set(struct drm_encoder *encoder, { struct drm_device *dev = encoder->dev; struct drm_i915_private *dev_priv = dev->dev_private; - struct intel_lvds *intel_lvds = enc_to_intel_lvds(encoder); + struct intel_lvds *intel_lvds = to_intel_lvds(encoder); /* * The LVDS pin pair will already have been turned on in the @@ -467,35 +472,23 @@ static enum drm_connector_status intel_lvds_detect(struct drm_connector *connect */ static int intel_lvds_get_modes(struct drm_connector *connector) { + struct intel_lvds *intel_lvds = intel_attached_lvds(connector); struct drm_device *dev = connector->dev; - struct drm_i915_private *dev_priv = dev->dev_private; + struct drm_display_mode *mode; - if (dev_priv->lvds_edid_good) { - struct intel_encoder *encoder = intel_attached_encoder(connector); - int ret = intel_ddc_get_modes(connector, encoder->ddc_bus); + if (intel_lvds->edid_good) { + int ret = intel_ddc_get_modes(connector, + intel_lvds->base.ddc_bus); if (ret) return ret; } - /* Didn't get an EDID, so - * Set wide sync ranges so we get all modes - * handed to valid_mode for checking - */ - connector->display_info.min_vfreq = 0; - connector->display_info.max_vfreq = 200; - connector->display_info.min_hfreq = 0; - connector->display_info.max_hfreq = 200; - - if (dev_priv->panel_fixed_mode != NULL) { - struct drm_display_mode *mode; + mode = drm_mode_duplicate(dev, intel_lvds->fixed_mode); + if (mode == 0) + return 0; - mode = drm_mode_duplicate(dev, dev_priv->panel_fixed_mode); - drm_mode_probed_add(connector, mode); - - return 1; - } - - return 0; + drm_mode_probed_add(connector, mode); + return 1; } static int intel_no_modeset_on_lid_dmi_callback(const struct dmi_system_id *id) @@ -584,18 +577,17 @@ static int intel_lvds_set_property(struct drm_connector *connector, struct drm_property *property, uint64_t value) { + struct intel_lvds *intel_lvds = intel_attached_lvds(connector); struct drm_device *dev = connector->dev; - if (property == dev->mode_config.scaling_mode_property && - connector->encoder) { - struct drm_crtc *crtc = connector->encoder->crtc; - struct drm_encoder *encoder = connector->encoder; - struct intel_lvds *intel_lvds = enc_to_intel_lvds(encoder); + if (property == dev->mode_config.scaling_mode_property) { + struct drm_crtc *crtc = intel_lvds->base.base.crtc; if (value == DRM_MODE_SCALE_NONE) { DRM_DEBUG_KMS("no scaling not supported\n"); - return 0; + return -EINVAL; } + if (intel_lvds->fitting_mode == value) { /* the LVDS scaling property is not changed */ return 0; @@ -723,15 +715,14 @@ static const struct dmi_system_id intel_no_lvds[] = { * Find the reduced downclock for LVDS in EDID. */ static void intel_find_lvds_downclock(struct drm_device *dev, - struct drm_connector *connector) + struct drm_display_mode *fixed_mode, + struct drm_connector *connector) { struct drm_i915_private *dev_priv = dev->dev_private; - struct drm_display_mode *scan, *panel_fixed_mode; + struct drm_display_mode *scan; int temp_downclock; - panel_fixed_mode = dev_priv->panel_fixed_mode; - temp_downclock = panel_fixed_mode->clock; - + temp_downclock = fixed_mode->clock; list_for_each_entry(scan, &connector->probed_modes, head) { /* * If one mode has the same resolution with the fixed_panel @@ -740,14 +731,14 @@ static void intel_find_lvds_downclock(struct drm_device *dev, * case we can set the different FPx0/1 to dynamically select * between low and high frequency. */ - if (scan->hdisplay == panel_fixed_mode->hdisplay && - scan->hsync_start == panel_fixed_mode->hsync_start && - scan->hsync_end == panel_fixed_mode->hsync_end && - scan->htotal == panel_fixed_mode->htotal && - scan->vdisplay == panel_fixed_mode->vdisplay && - scan->vsync_start == panel_fixed_mode->vsync_start && - scan->vsync_end == panel_fixed_mode->vsync_end && - scan->vtotal == panel_fixed_mode->vtotal) { + if (scan->hdisplay == fixed_mode->hdisplay && + scan->hsync_start == fixed_mode->hsync_start && + scan->hsync_end == fixed_mode->hsync_end && + scan->htotal == fixed_mode->htotal && + scan->vdisplay == fixed_mode->vdisplay && + scan->vsync_start == fixed_mode->vsync_start && + scan->vsync_end == fixed_mode->vsync_end && + scan->vtotal == fixed_mode->vtotal) { if (scan->clock < temp_downclock) { /* * The downclock is already found. But we @@ -757,16 +748,14 @@ static void intel_find_lvds_downclock(struct drm_device *dev, } } } - if (temp_downclock < panel_fixed_mode->clock && - i915_lvds_downclock) { + if (temp_downclock < fixed_mode->clock && i915_lvds_downclock) { /* We found the downclock for LVDS. */ dev_priv->lvds_downclock_avail = 1; dev_priv->lvds_downclock = temp_downclock; DRM_DEBUG_KMS("LVDS downclock is found in EDID. " - "Normal clock %dKhz, downclock %dKhz\n", - panel_fixed_mode->clock, temp_downclock); + "Normal clock %dKhz, downclock %dKhz\n", + fixed_mode->clock, temp_downclock); } - return; } /* @@ -921,26 +910,38 @@ void intel_lvds_init(struct drm_device *dev) * Attempt to get the fixed panel mode from DDC. Assume that the * preferred mode is the right one. */ - dev_priv->lvds_edid_good = true; - + intel_lvds->edid_good = true; if (!intel_ddc_get_modes(connector, intel_encoder->ddc_bus)) - dev_priv->lvds_edid_good = false; + intel_lvds->edid_good = false; + + if (!intel_lvds->edid_good) { + /* Didn't get an EDID, so + * Set wide sync ranges so we get all modes + * handed to valid_mode for checking + */ + connector->display_info.min_vfreq = 0; + connector->display_info.max_vfreq = 200; + connector->display_info.min_hfreq = 0; + connector->display_info.max_hfreq = 200; + } list_for_each_entry(scan, &connector->probed_modes, head) { if (scan->type & DRM_MODE_TYPE_PREFERRED) { - dev_priv->panel_fixed_mode = + intel_lvds->fixed_mode = drm_mode_duplicate(dev, scan); - intel_find_lvds_downclock(dev, connector); + intel_find_lvds_downclock(dev, + intel_lvds->fixed_mode, + connector); goto out; } } /* Failed to get EDID, what about VBT? */ if (dev_priv->lfp_lvds_vbt_mode) { - dev_priv->panel_fixed_mode = + intel_lvds->fixed_mode = drm_mode_duplicate(dev, dev_priv->lfp_lvds_vbt_mode); - if (dev_priv->panel_fixed_mode) { - dev_priv->panel_fixed_mode->type |= + if (intel_lvds->fixed_mode) { + intel_lvds->fixed_mode->type |= DRM_MODE_TYPE_PREFERRED; goto out; } @@ -961,16 +962,16 @@ void intel_lvds_init(struct drm_device *dev) crtc = intel_get_crtc_for_pipe(dev, pipe); if (crtc && (lvds & LVDS_PORT_EN)) { - dev_priv->panel_fixed_mode = intel_crtc_mode_get(dev, crtc); - if (dev_priv->panel_fixed_mode) { - dev_priv->panel_fixed_mode->type |= + intel_lvds->fixed_mode = intel_crtc_mode_get(dev, crtc); + if (intel_lvds->fixed_mode) { + intel_lvds->fixed_mode->type |= DRM_MODE_TYPE_PREFERRED; goto out; } } /* If we still don't have a mode after all that, give up. */ - if (!dev_priv->panel_fixed_mode) + if (!intel_lvds->fixed_mode) goto failed; out: -- cgit v1.1 From 6b383a7f6378f193c30200435d8170f95916b5f0 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Mon, 13 Sep 2010 13:54:26 +0100 Subject: drm/i915: Share crtc setup and teardown between dpms and disable/enable This closes a couple of corner cases where we introduced and forgot about a couple of routines that need to be called when disabling the crtc and then re-enabling it. The code needs to be moved again so that the common bits are shared across generations. Signed-off-by: Chris Wilson --- drivers/gpu/drm/i915/intel_display.c | 125 +++++++++++++---------------------- drivers/gpu/drm/i915/intel_drv.h | 2 +- 2 files changed, 46 insertions(+), 81 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 0004534..1e2a17d 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -44,7 +44,7 @@ bool intel_pipe_has_type (struct drm_crtc *crtc, int type); static void intel_update_watermarks(struct drm_device *dev); static void intel_increase_pllclock(struct drm_crtc *crtc); -static void intel_crtc_update_cursor(struct drm_crtc *crtc); +static void intel_crtc_update_cursor(struct drm_crtc *crtc, bool on); typedef struct { /* given values */ @@ -1927,6 +1927,26 @@ static void intel_flush_display_plane(struct drm_device *dev, I915_WRITE(reg, I915_READ(reg)); } +/* + * When we disable a pipe, we need to clear any pending scanline wait events + * to avoid hanging the ring, which we assume we are waiting on. + */ +static void intel_clear_scanline_wait(struct drm_device *dev) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + u32 tmp; + + if (IS_GEN2(dev)) + /* Can't break the hang on i8xx */ + return; + + tmp = I915_READ(PRB0_CTL); + if (tmp & RING_WAIT) { + I915_WRITE(PRB0_CTL, tmp); + POSTING_READ(PRB0_CTL); + } +} + static void ironlake_crtc_enable(struct drm_crtc *crtc) { struct drm_device *dev = crtc->dev; @@ -1936,6 +1956,8 @@ static void ironlake_crtc_enable(struct drm_crtc *crtc) int plane = intel_crtc->plane; u32 reg, temp; + intel_update_watermarks(dev); + if (intel_pipe_has_type(crtc, INTEL_OUTPUT_LVDS)) { temp = I915_READ(PCH_LVDS); if ((temp & LVDS_PORT_EN) == 0) @@ -2082,6 +2104,7 @@ static void ironlake_crtc_enable(struct drm_crtc *crtc) intel_crtc_load_lut(crtc); intel_update_fbc(dev); + intel_crtc_update_cursor(crtc, true); } static void ironlake_crtc_disable(struct drm_crtc *crtc) @@ -2094,6 +2117,7 @@ static void ironlake_crtc_disable(struct drm_crtc *crtc) u32 reg, temp; drm_vblank_off(dev, pipe); + intel_crtc_update_cursor(crtc, false); /* Disable display plane */ reg = DSPCNTR(plane); @@ -2220,6 +2244,10 @@ static void ironlake_crtc_disable(struct drm_crtc *crtc) /* Wait for the clocks to turn off. */ POSTING_READ(reg); udelay(100); + + intel_update_watermarks(dev); + intel_update_fbc(dev); + intel_clear_scanline_wait(dev); } static void ironlake_crtc_dpms(struct drm_crtc *crtc, int mode) @@ -2270,6 +2298,8 @@ static void i9xx_crtc_enable(struct drm_crtc *crtc) int plane = intel_crtc->plane; u32 reg, temp; + intel_update_watermarks(dev); + /* Enable the DPLL */ reg = DPLL(pipe); temp = I915_READ(reg); @@ -2312,6 +2342,7 @@ static void i9xx_crtc_enable(struct drm_crtc *crtc) /* Give the overlay scaler a chance to enable if it's on this pipe */ intel_crtc_dpms_overlay(intel_crtc, true); + intel_crtc_update_cursor(crtc, true); } static void i9xx_crtc_disable(struct drm_crtc *crtc) @@ -2325,6 +2356,7 @@ static void i9xx_crtc_disable(struct drm_crtc *crtc) /* Give the overlay scaler a chance to disable if it's on this pipe */ intel_crtc_dpms_overlay(intel_crtc, false); + intel_crtc_update_cursor(crtc, false); drm_vblank_off(dev, pipe); if (dev_priv->cfb_plane == plane && @@ -2346,7 +2378,7 @@ static void i9xx_crtc_disable(struct drm_crtc *crtc) /* Don't disable pipe A or pipe A PLLs if needed */ if (pipe == 0 && (dev_priv->quirks & QUIRK_PIPEA_FORCE)) - return; + goto done; /* Next, disable display pipes */ reg = PIPECONF(pipe); @@ -2368,6 +2400,11 @@ static void i9xx_crtc_disable(struct drm_crtc *crtc) POSTING_READ(reg); udelay(150); } + +done: + intel_update_fbc(dev); + intel_update_watermarks(dev); + intel_clear_scanline_wait(dev); } static void i9xx_crtc_dpms(struct drm_crtc *crtc, int mode) @@ -2387,26 +2424,6 @@ static void i9xx_crtc_dpms(struct drm_crtc *crtc, int mode) } } -/* - * When we disable a pipe, we need to clear any pending scanline wait events - * to avoid hanging the ring, which we assume we are waiting on. - */ -static void intel_clear_scanline_wait(struct drm_device *dev) -{ - struct drm_i915_private *dev_priv = dev->dev_private; - u32 tmp; - - if (IS_GEN2(dev)) - /* Can't break the hang on i8xx */ - return; - - tmp = I915_READ(PRB0_CTL); - if (tmp & RING_WAIT) { - I915_WRITE(PRB0_CTL, tmp); - POSTING_READ(PRB0_CTL); - } -} - /** * Sets the power management mode of the pipe and plane. */ @@ -2423,34 +2440,9 @@ static void intel_crtc_dpms(struct drm_crtc *crtc, int mode) return; intel_crtc->dpms_mode = mode; - intel_crtc->cursor_on = mode == DRM_MODE_DPMS_ON; - - /* When switching on the display, ensure that SR is disabled - * with multiple pipes prior to enabling to new pipe. - * - * When switching off the display, make sure the cursor is - * properly hidden and there are no pending waits prior to - * disabling the pipe. - */ - if (mode == DRM_MODE_DPMS_ON) - intel_update_watermarks(dev); - else - intel_crtc_update_cursor(crtc); dev_priv->display.dpms(crtc, mode); - if (mode == DRM_MODE_DPMS_ON) { - intel_crtc_update_cursor(crtc); - } else { - /* XXX Note that this is not a complete solution, but a hack - * to avoid the most frequently hit hang. - */ - intel_clear_scanline_wait(dev); - - intel_update_watermarks(dev); - } - intel_update_fbc(dev); - if (!dev->primary->master) return; @@ -2485,50 +2477,22 @@ static void intel_crtc_dpms(struct drm_crtc *crtc, int mode) */ static void i9xx_crtc_prepare(struct drm_crtc *crtc) { - struct drm_device *dev = crtc->dev; - struct intel_crtc *intel_crtc = to_intel_crtc(crtc); - - intel_crtc->cursor_on = false; - intel_crtc_update_cursor(crtc); - i9xx_crtc_disable(crtc); - intel_clear_scanline_wait(dev); } static void i9xx_crtc_commit(struct drm_crtc *crtc) { - struct drm_device *dev = crtc->dev; - struct intel_crtc *intel_crtc = to_intel_crtc(crtc); - - intel_update_watermarks(dev); i9xx_crtc_enable(crtc); - - intel_crtc->cursor_on = true; - intel_crtc_update_cursor(crtc); } static void ironlake_crtc_prepare(struct drm_crtc *crtc) { - struct drm_device *dev = crtc->dev; - struct intel_crtc *intel_crtc = to_intel_crtc(crtc); - - intel_crtc->cursor_on = false; - intel_crtc_update_cursor(crtc); - ironlake_crtc_disable(crtc); - intel_clear_scanline_wait(dev); } static void ironlake_crtc_commit(struct drm_crtc *crtc) { - struct drm_device *dev = crtc->dev; - struct intel_crtc *intel_crtc = to_intel_crtc(crtc); - - intel_update_watermarks(dev); ironlake_crtc_enable(crtc); - - intel_crtc->cursor_on = true; - intel_crtc_update_cursor(crtc); } void intel_encoder_prepare (struct drm_encoder *encoder) @@ -3615,7 +3579,7 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc, } /* Ensure that the cursor is valid for the new mode before changing... */ - intel_crtc_update_cursor(crtc); + intel_crtc_update_cursor(crtc, true); if (is_lvds && dev_priv->lvds_downclock_avail) { has_reduced_clock = limit->find_pll(limit, crtc, @@ -4225,7 +4189,8 @@ static void i9xx_update_cursor(struct drm_crtc *crtc, u32 base) } /* If no-part of the cursor is visible on the framebuffer, then the GPU may hang... */ -static void intel_crtc_update_cursor(struct drm_crtc *crtc) +static void intel_crtc_update_cursor(struct drm_crtc *crtc, + bool on) { struct drm_device *dev = crtc->dev; struct drm_i915_private *dev_priv = dev->dev_private; @@ -4238,7 +4203,7 @@ static void intel_crtc_update_cursor(struct drm_crtc *crtc) pos = 0; - if (intel_crtc->cursor_on && crtc->fb) { + if (on && crtc->enabled && crtc->fb) { base = intel_crtc->cursor_addr; if (x > (int) crtc->fb->width) base = 0; @@ -4370,7 +4335,7 @@ static int intel_crtc_cursor_set(struct drm_crtc *crtc, intel_crtc->cursor_width = width; intel_crtc->cursor_height = height; - intel_crtc_update_cursor(crtc); + intel_crtc_update_cursor(crtc, true); return 0; fail_unpin: @@ -4389,7 +4354,7 @@ static int intel_crtc_cursor_move(struct drm_crtc *crtc, int x, int y) intel_crtc->cursor_x = x; intel_crtc->cursor_y = y; - intel_crtc_update_cursor(crtc); + intel_crtc_update_cursor(crtc, true); return 0; } diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index 7e2646f..c0891b1 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -180,7 +180,7 @@ struct intel_crtc { uint32_t cursor_addr; int16_t cursor_x, cursor_y; int16_t cursor_width, cursor_height; - bool cursor_visible, cursor_on; + bool cursor_visible; }; #define to_intel_crtc(x) container_of(x, struct intel_crtc, base) -- cgit v1.1 From f7abfe8b281991c66406c42c1a6c6c9ee0daa0ff Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Mon, 13 Sep 2010 14:19:16 +0100 Subject: drm/i915: Fix an overlay regression from 7e7d76c When separating out the prepare/commit into its own separate functions we overlooked that the intel_crtc->dpms_mode was being used elsewhere to check on the actual status of the pipe. Track that bit of logic separately from the actual dpms mode, so there is no confusion should we be able to handle multiple dpms modes, nor any semantic conflict between prepare/commit and dpms. Signed-off-by: Chris Wilson --- drivers/gpu/drm/i915/intel_display.c | 18 +++++++++++++++++- drivers/gpu/drm/i915/intel_drv.h | 1 + drivers/gpu/drm/i915/intel_overlay.c | 8 +++----- 3 files changed, 21 insertions(+), 6 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 1e2a17d..a54b701 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -1956,6 +1956,10 @@ static void ironlake_crtc_enable(struct drm_crtc *crtc) int plane = intel_crtc->plane; u32 reg, temp; + if (intel_crtc->active) + return; + + intel_crtc->active = true; intel_update_watermarks(dev); if (intel_pipe_has_type(crtc, INTEL_OUTPUT_LVDS)) { @@ -2116,6 +2120,9 @@ static void ironlake_crtc_disable(struct drm_crtc *crtc) int plane = intel_crtc->plane; u32 reg, temp; + if (!intel_crtc->active) + return; + drm_vblank_off(dev, pipe); intel_crtc_update_cursor(crtc, false); @@ -2245,6 +2252,7 @@ static void ironlake_crtc_disable(struct drm_crtc *crtc) POSTING_READ(reg); udelay(100); + intel_crtc->active = false; intel_update_watermarks(dev); intel_update_fbc(dev); intel_clear_scanline_wait(dev); @@ -2298,6 +2306,10 @@ static void i9xx_crtc_enable(struct drm_crtc *crtc) int plane = intel_crtc->plane; u32 reg, temp; + if (intel_crtc->active) + return; + + intel_crtc->active = true; intel_update_watermarks(dev); /* Enable the DPLL */ @@ -2354,6 +2366,9 @@ static void i9xx_crtc_disable(struct drm_crtc *crtc) int plane = intel_crtc->plane; u32 reg, temp; + if (!intel_crtc->active) + return; + /* Give the overlay scaler a chance to disable if it's on this pipe */ intel_crtc_dpms_overlay(intel_crtc, false); intel_crtc_update_cursor(crtc, false); @@ -2402,6 +2417,7 @@ static void i9xx_crtc_disable(struct drm_crtc *crtc) } done: + intel_crtc->active = false; intel_update_fbc(dev); intel_update_watermarks(dev); intel_clear_scanline_wait(dev); @@ -3463,7 +3479,7 @@ static void intel_update_watermarks(struct drm_device *dev) /* Get the clock config from both planes */ list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { struct intel_crtc *intel_crtc = to_intel_crtc(crtc); - if (intel_crtc->dpms_mode == DRM_MODE_DPMS_ON) { + if (intel_crtc->active) { enabled++; if (intel_crtc->plane == 0) { DRM_DEBUG_KMS("plane A (pipe %d) clock: %d\n", diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index c0891b1..5171b05 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -169,6 +169,7 @@ struct intel_crtc { enum plane plane; u8 lut_r[256], lut_g[256], lut_b[256]; int dpms_mode; + bool active; /* is the crtc on? independent of the dpms mode */ bool busy; /* is scanout buffer being updated frequently? */ struct timer_list idle_timer; bool lowfreq_avail; diff --git a/drivers/gpu/drm/i915/intel_overlay.c b/drivers/gpu/drm/i915/intel_overlay.c index 3dff161..c4699c9 100644 --- a/drivers/gpu/drm/i915/intel_overlay.c +++ b/drivers/gpu/drm/i915/intel_overlay.c @@ -875,15 +875,13 @@ static int check_overlay_possible_on_crtc(struct intel_overlay *overlay, struct intel_crtc *crtc) { drm_i915_private_t *dev_priv = overlay->dev->dev_private; - u32 pipeconf; - if (!crtc->base.enabled || crtc->dpms_mode != DRM_MODE_DPMS_ON) + if (!crtc->active) return -EINVAL; - pipeconf = I915_READ(PIPECONF(crtc->pipe)); - /* can't use the overlay with double wide pipe */ - if (!IS_I965G(overlay->dev) && pipeconf & PIPECONF_DOUBLE_WIDE) + if (!IS_I965G(overlay->dev) && + (I915_READ(PIPECONF(crtc->pipe)) & (PIPECONF_DOUBLE_WIDE | PIPECONF_ENABLE)) != PIPECONF_ENABLE) return -EINVAL; return 0; -- cgit v1.1 From e65d9305f528d4f354378690135ee8d1c60ec0a5 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Mon, 13 Sep 2010 16:58:39 +0100 Subject: drm/i915: Initialize intel_crtc->active Fix a regression in the previous regression fix... In order to turn off the pipes entirely upon the first modeset, we pretend that BIOS (or earlier module incarnation) left them active. The first task performed by setup_initial_configuration() is to disable all pipes and so to avoid skipping that step and so to ensure a known configuration we need to mark all the crtcs as active. Signed-off-by: Chris Wilson --- drivers/gpu/drm/i915/intel_display.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index a54b701..e4fd7a3 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -5201,6 +5201,7 @@ static void intel_crtc_init(struct drm_device *dev, int pipe) intel_crtc->cursor_addr = 0; intel_crtc->dpms_mode = -1; + intel_crtc->active = true; /* force the pipe off on setup_init_config */ if (HAS_PCH_SPLIT(dev)) { intel_helper_funcs.prepare = ironlake_crtc_prepare; -- cgit v1.1 From e2e767abd85806d05a5266b3b112baaf80ee3382 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Mon, 13 Sep 2010 16:53:12 +0100 Subject: drm/i915: Remove redundant initialisation of crtc->pipe Signed-off-by: Chris Wilson --- drivers/gpu/drm/i915/intel_display.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index e4fd7a3..16ae345 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -5178,8 +5178,6 @@ static void intel_crtc_init(struct drm_device *dev, int pipe) drm_crtc_init(dev, &intel_crtc->base, &intel_crtc_funcs); drm_mode_crtc_set_gamma_size(&intel_crtc->base, 256); - intel_crtc->pipe = pipe; - intel_crtc->plane = pipe; for (i = 0; i < 256; i++) { intel_crtc->lut_r[i] = i; intel_crtc->lut_g[i] = i; @@ -5189,9 +5187,9 @@ static void intel_crtc_init(struct drm_device *dev, int pipe) /* Swap pipes & planes for FBC on pre-965 */ intel_crtc->pipe = pipe; intel_crtc->plane = pipe; - if (IS_MOBILE(dev) && (IS_I9XX(dev) && !IS_I965G(dev))) { + if (IS_MOBILE(dev) && IS_GEN3(dev)) { DRM_DEBUG_KMS("swapping pipes & planes for FBC\n"); - intel_crtc->plane = ((pipe == 0) ? 1 : 0); + intel_crtc->plane = !pipe; } BUG_ON(pipe >= ARRAY_SIZE(dev_priv->plane_to_crtc_mapping) || -- cgit v1.1 From b3b079dbef06c7f775178d561a4c8e47b7447139 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Mon, 13 Sep 2010 23:44:34 +0100 Subject: drm/i915: Reduce hangcheck frequency By reducing the hangcheck frequency we check less often, conserving resources, and still detect a lock up quickly. On a fast machine with a slow GPU (like a Core2 paired with a 945G) it is easy for the hangcheck to misfire as we check too fast. Also once hung and if we fail to completely reset the chip, we have a nasty habit of proclaming a hang many times a second and generating a strobe-like display. Signed-off-by: Chris Wilson --- drivers/gpu/drm/i915/i915_drv.h | 2 +- drivers/gpu/drm/i915/i915_gem.c | 6 ++++-- drivers/gpu/drm/i915/i915_irq.c | 9 ++++++--- 3 files changed, 11 insertions(+), 6 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 232555e..70cbe3c 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -299,7 +299,7 @@ typedef struct drm_i915_private { int num_pipe; /* For hangcheck timer */ -#define DRM_I915_HANGCHECK_PERIOD 75 /* in jiffies */ +#define DRM_I915_HANGCHECK_PERIOD 250 /* in ms */ struct timer_list hangcheck_timer; int hangcheck_count; uint32_t last_acthd; diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index e0b7ddc..9391765 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -1639,9 +1639,11 @@ i915_add_request(struct drm_device *dev, } if (!dev_priv->mm.suspended) { - mod_timer(&dev_priv->hangcheck_timer, jiffies + DRM_I915_HANGCHECK_PERIOD); + mod_timer(&dev_priv->hangcheck_timer, + jiffies + msecs_to_jiffies(DRM_I915_HANGCHECK_PERIOD)); if (was_empty) - queue_delayed_work(dev_priv->wq, &dev_priv->mm.retire_work, HZ); + queue_delayed_work(dev_priv->wq, + &dev_priv->mm.retire_work, HZ); } return seqno; } diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c index bc8438d..e64b8ea 100644 --- a/drivers/gpu/drm/i915/i915_irq.c +++ b/drivers/gpu/drm/i915/i915_irq.c @@ -328,7 +328,8 @@ static irqreturn_t ironlake_irq_handler(struct drm_device *dev) trace_i915_gem_request_complete(dev, seqno); DRM_WAKEUP(&dev_priv->render_ring.irq_queue); dev_priv->hangcheck_count = 0; - mod_timer(&dev_priv->hangcheck_timer, jiffies + DRM_I915_HANGCHECK_PERIOD); + mod_timer(&dev_priv->hangcheck_timer, + jiffies + msecs_to_jiffies(DRM_I915_HANGCHECK_PERIOD)); } if (gt_iir & GT_BSD_USER_INTERRUPT) DRM_WAKEUP(&dev_priv->bsd_ring.irq_queue); @@ -1018,7 +1019,8 @@ irqreturn_t i915_driver_irq_handler(DRM_IRQ_ARGS) trace_i915_gem_request_complete(dev, seqno); DRM_WAKEUP(&dev_priv->render_ring.irq_queue); dev_priv->hangcheck_count = 0; - mod_timer(&dev_priv->hangcheck_timer, jiffies + DRM_I915_HANGCHECK_PERIOD); + mod_timer(&dev_priv->hangcheck_timer, + jiffies + msecs_to_jiffies(DRM_I915_HANGCHECK_PERIOD)); } if (HAS_BSD(dev) && (iir & I915_BSD_USER_INTERRUPT)) @@ -1394,7 +1396,8 @@ void i915_hangcheck_elapsed(unsigned long data) out: /* Reset timer case chip hangs without another request being added */ - mod_timer(&dev_priv->hangcheck_timer, jiffies + DRM_I915_HANGCHECK_PERIOD); + mod_timer(&dev_priv->hangcheck_timer, + jiffies + msecs_to_jiffies(DRM_I915_HANGCHECK_PERIOD)); } /* drm_dma.h hooks -- cgit v1.1 From 7213342db58adb7b8e399a00fc423951d7f75369 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Mon, 13 Sep 2010 23:56:38 +0100 Subject: drm/i915: Consolidate flushing the display plane Signed-off-by: Chris Wilson --- drivers/gpu/drm/i915/i915_drv.h | 1 - drivers/gpu/drm/i915/i915_gem.c | 42 +++++++++--------------------------- drivers/gpu/drm/i915/intel_display.c | 16 ++++++-------- drivers/gpu/drm/i915/intel_fb.c | 8 +------ 4 files changed, 17 insertions(+), 50 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 70cbe3c..24b7796 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -1024,7 +1024,6 @@ void i915_gem_free_all_phys_object(struct drm_device *dev); int i915_gem_object_get_pages(struct drm_gem_object *obj, gfp_t gfpmask); void i915_gem_object_put_pages(struct drm_gem_object *obj); void i915_gem_release(struct drm_device * dev, struct drm_file *file_priv); -int i915_gem_object_flush_write_domain(struct drm_gem_object *obj); void i915_gem_shrinker_init(void); void i915_gem_shrinker_exit(void); diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index 9391765..328f8c9 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -2645,26 +2645,6 @@ i915_gem_object_flush_cpu_write_domain(struct drm_gem_object *obj) old_write_domain); } -int -i915_gem_object_flush_write_domain(struct drm_gem_object *obj) -{ - int ret = 0; - - switch (obj->write_domain) { - case I915_GEM_DOMAIN_GTT: - i915_gem_object_flush_gtt_write_domain(obj); - break; - case I915_GEM_DOMAIN_CPU: - i915_gem_object_flush_cpu_write_domain(obj); - break; - default: - ret = i915_gem_object_flush_gpu_write_domain(obj, true); - break; - } - - return ret; -} - /** * Moves a single object to the GTT read, and possibly write domain. * @@ -2686,21 +2666,16 @@ i915_gem_object_set_to_gtt_domain(struct drm_gem_object *obj, int write) if (ret != 0) return ret; - old_write_domain = obj->write_domain; - old_read_domains = obj->read_domains; + i915_gem_object_flush_cpu_write_domain(obj); - /* If we're writing through the GTT domain, then CPU and GPU caches - * will need to be invalidated at next use. - */ if (write) { ret = i915_gem_object_wait_rendering(obj); if (ret) return ret; - - obj->read_domains &= I915_GEM_DOMAIN_GTT; } - i915_gem_object_flush_cpu_write_domain(obj); + old_write_domain = obj->write_domain; + old_read_domains = obj->read_domains; /* It should now be out of any other write domains, and we can update * the domain values for our changes. @@ -2708,6 +2683,7 @@ i915_gem_object_set_to_gtt_domain(struct drm_gem_object *obj, int write) BUG_ON((obj->write_domain & ~I915_GEM_DOMAIN_GTT) != 0); obj->read_domains |= I915_GEM_DOMAIN_GTT; if (write) { + obj->read_domains = I915_GEM_DOMAIN_GTT; obj->write_domain = I915_GEM_DOMAIN_GTT; obj_priv->dirty = 1; } @@ -2773,6 +2749,12 @@ i915_gem_object_set_to_cpu_domain(struct drm_gem_object *obj, int write) */ i915_gem_object_set_to_full_cpu_read_domain(obj); + if (write) { + ret = i915_gem_object_wait_rendering(obj); + if (ret) + return ret; + } + old_write_domain = obj->write_domain; old_read_domains = obj->read_domains; @@ -2792,10 +2774,6 @@ i915_gem_object_set_to_cpu_domain(struct drm_gem_object *obj, int write) * need to be invalidated at next use. */ if (write) { - ret = i915_gem_object_wait_rendering(obj); - if (ret) - return ret; - obj->read_domains &= I915_GEM_DOMAIN_CPU; obj->write_domain = I915_GEM_DOMAIN_CPU; } diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 16ae345..810ed2d 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -1448,6 +1448,12 @@ intel_pin_and_fence_fb_obj(struct drm_device *dev, struct drm_gem_object *obj) if (ret != 0) return ret; + ret = i915_gem_object_set_to_display_plane(obj); + if (ret != 0) { + i915_gem_object_unpin(obj); + return ret; + } + /* Install a fence for tiled scan-out. Pre-i965 always needs a * fence, whereas 965+ only requires a fence if using * framebuffer compression. For simplicity, we always install @@ -1589,13 +1595,6 @@ intel_pipe_set_base(struct drm_crtc *crtc, int x, int y, return ret; } - ret = i915_gem_object_set_to_display_plane(obj); - if (ret != 0) { - i915_gem_object_unpin(obj); - mutex_unlock(&dev->struct_mutex); - return ret; - } - ret = intel_pipe_set_base_atomic(crtc, crtc->fb, x, y); if (ret) { i915_gem_object_unpin(obj); @@ -5043,9 +5042,6 @@ static int intel_crtc_page_flip(struct drm_crtc *crtc, drm_gem_object_reference(obj); crtc->fb = fb; - ret = i915_gem_object_flush_write_domain(obj); - if (ret) - goto cleanup_objs; ret = drm_vblank_get(dev, intel_crtc->pipe); if (ret) diff --git a/drivers/gpu/drm/i915/intel_fb.c b/drivers/gpu/drm/i915/intel_fb.c index 0ee4a8c..e2d13e3 100644 --- a/drivers/gpu/drm/i915/intel_fb.c +++ b/drivers/gpu/drm/i915/intel_fb.c @@ -93,19 +93,13 @@ static int intelfb_create(struct intel_fbdev *ifbdev, mutex_lock(&dev->struct_mutex); + /* Flush everything out, we'll be doing GTT only from now on */ ret = intel_pin_and_fence_fb_obj(dev, fbo); if (ret) { DRM_ERROR("failed to pin fb: %d\n", ret); goto out_unref; } - /* Flush everything out, we'll be doing GTT only from now on */ - ret = i915_gem_object_set_to_gtt_domain(fbo, 1); - if (ret) { - DRM_ERROR("failed to bind fb: %d.\n", ret); - goto out_unpin; - } - info = framebuffer_alloc(0, device); if (!info) { ret = -ENOMEM; -- cgit v1.1 From 0bc23aad3b67ca0cd7480dec0b7652d9b8686432 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Tue, 14 Sep 2010 10:22:23 +0100 Subject: drm/i915: Fix regression in ba3d8d749b I pulled the wrong version of the patch from Daniel Vetter which was missing the read barriers -- and the one that was causing all the trouble was from i915_gem_object_put_fence_reg(), leading to GPU hangs on gen3. Signed-off-by: Chris Wilson --- drivers/gpu/drm/i915/i915_gem.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index 328f8c9..4a0d85c 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -2430,12 +2430,16 @@ i915_gem_object_put_fence_reg(struct drm_gem_object *obj) int ret; ret = i915_gem_object_flush_gpu_write_domain(obj, false); - if (ret != 0) + if (ret) + return ret; + + ret = i915_gem_object_wait_rendering(obj); + if (ret) return ret; } i915_gem_object_flush_gtt_write_domain(obj); - i915_gem_clear_fence_reg (obj); + i915_gem_clear_fence_reg(obj); return 0; } -- cgit v1.1 From 9e76e7b8bd716413cfd722a807aa22723f3a895f Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Tue, 14 Sep 2010 12:12:11 +0100 Subject: agp/intel: Use macro to set the count of the size array It's a fixed size array so let the compiler do the hard work of updating all the call sites. Signed-off-by: Chris Wilson --- drivers/char/agp/intel-gtt.c | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/drivers/char/agp/intel-gtt.c b/drivers/char/agp/intel-gtt.c index 9cb7c98..dedf05d 100644 --- a/drivers/char/agp/intel-gtt.c +++ b/drivers/char/agp/intel-gtt.c @@ -539,8 +539,7 @@ static unsigned long intel_i810_mask_memory(struct agp_bridge_data *bridge, return addr | bridge->driver->masks[type].mask; } -static struct aper_size_info_fixed intel_fake_agp_sizes[] = -{ +static const struct aper_size_info_fixed const intel_fake_agp_sizes[] = { {128, 32768, 5}, /* The 64M mode still requires a 128k gatt */ {64, 16384, 5}, @@ -833,16 +832,17 @@ static int intel_gtt_init(void) static int intel_fake_agp_fetch_size(void) { + int num_sizes = ARRAY_SIZE(intel_fake_agp_sizes); unsigned int aper_size; int i; - int num_sizes = ARRAY_SIZE(intel_fake_agp_sizes); aper_size = (intel_private.base.gtt_mappable_entries << PAGE_SHIFT) / MB(1); for (i = 0; i < num_sizes; i++) { if (aper_size == intel_fake_agp_sizes[i].size) { - agp_bridge->current_size = intel_fake_agp_sizes + i; + agp_bridge->current_size = + (void *) (intel_fake_agp_sizes + i); return aper_size; } } @@ -1363,9 +1363,9 @@ static const struct agp_bridge_driver intel_810_driver = { static const struct agp_bridge_driver intel_830_driver = { .owner = THIS_MODULE, - .aperture_sizes = intel_fake_agp_sizes, .size_type = FIXED_APER_SIZE, - .num_aperture_sizes = 4, + .aperture_sizes = intel_fake_agp_sizes, + .num_aperture_sizes = ARRAY_SIZE(intel_fake_agp_sizes), .needs_scratch_page = true, .configure = intel_i830_configure, .fetch_size = intel_fake_agp_fetch_size, @@ -1390,9 +1390,9 @@ static const struct agp_bridge_driver intel_830_driver = { static const struct agp_bridge_driver intel_915_driver = { .owner = THIS_MODULE, - .aperture_sizes = intel_fake_agp_sizes, .size_type = FIXED_APER_SIZE, - .num_aperture_sizes = 4, + .aperture_sizes = intel_fake_agp_sizes, + .num_aperture_sizes = ARRAY_SIZE(intel_fake_agp_sizes), .needs_scratch_page = true, .configure = intel_i9xx_configure, .fetch_size = intel_fake_agp_fetch_size, @@ -1423,9 +1423,9 @@ static const struct agp_bridge_driver intel_915_driver = { static const struct agp_bridge_driver intel_i965_driver = { .owner = THIS_MODULE, - .aperture_sizes = intel_fake_agp_sizes, .size_type = FIXED_APER_SIZE, - .num_aperture_sizes = 4, + .aperture_sizes = intel_fake_agp_sizes, + .num_aperture_sizes = ARRAY_SIZE(intel_fake_agp_sizes), .needs_scratch_page = true, .configure = intel_i9xx_configure, .fetch_size = intel_fake_agp_fetch_size, @@ -1456,9 +1456,9 @@ static const struct agp_bridge_driver intel_i965_driver = { static const struct agp_bridge_driver intel_gen6_driver = { .owner = THIS_MODULE, - .aperture_sizes = intel_fake_agp_sizes, .size_type = FIXED_APER_SIZE, - .num_aperture_sizes = 4, + .aperture_sizes = intel_fake_agp_sizes, + .num_aperture_sizes = ARRAY_SIZE(intel_fake_agp_sizes), .needs_scratch_page = true, .configure = intel_i9xx_configure, .fetch_size = intel_fake_agp_fetch_size, @@ -1489,9 +1489,9 @@ static const struct agp_bridge_driver intel_gen6_driver = { static const struct agp_bridge_driver intel_g33_driver = { .owner = THIS_MODULE, - .aperture_sizes = intel_fake_agp_sizes, .size_type = FIXED_APER_SIZE, - .num_aperture_sizes = 4, + .aperture_sizes = intel_fake_agp_sizes, + .num_aperture_sizes = ARRAY_SIZE(intel_fake_agp_sizes), .needs_scratch_page = true, .configure = intel_i9xx_configure, .fetch_size = intel_fake_agp_fetch_size, -- cgit v1.1 From 48b956c5a89c7b100ef3b818b6ccf759ab695383 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Tue, 14 Sep 2010 12:50:34 +0100 Subject: drm/i915: Push pipelining of display plane flushes to the caller This ensures that we do wait upon the flushes to complete if necessary and avoid the visual tears, whilst enabling pipelined page-flips. Signed-off-by: Chris Wilson --- drivers/gpu/drm/i915/i915_drv.h | 3 +- drivers/gpu/drm/i915/i915_gem.c | 8 ++++-- drivers/gpu/drm/i915/intel_display.c | 56 +++++++++++++++++++++--------------- drivers/gpu/drm/i915/intel_drv.h | 3 +- drivers/gpu/drm/i915/intel_fb.c | 2 +- 5 files changed, 43 insertions(+), 29 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 24b7796..b97d62d 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -1013,7 +1013,8 @@ void i915_gem_process_flushing_list(struct drm_device *dev, struct intel_ring_buffer *ring); int i915_gem_object_set_to_gtt_domain(struct drm_gem_object *obj, int write); -int i915_gem_object_set_to_display_plane(struct drm_gem_object *obj); +int i915_gem_object_set_to_display_plane(struct drm_gem_object *obj, + bool pipelined); int i915_gem_attach_phys_object(struct drm_device *dev, struct drm_gem_object *obj, int id, diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index 4a0d85c..85a3cf4 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -2597,6 +2597,7 @@ i915_gem_object_flush_gpu_write_domain(struct drm_gem_object *obj, /* Queue the GPU write cache flushing we need. */ old_write_domain = obj->write_domain; i915_gem_flush(dev, 0, obj->write_domain); + BUG_ON(obj->write_domain); trace_i915_gem_object_change_domain(obj, obj->read_domains, @@ -2704,7 +2705,8 @@ i915_gem_object_set_to_gtt_domain(struct drm_gem_object *obj, int write) * wait, as in modesetting process we're not supposed to be interrupted. */ int -i915_gem_object_set_to_display_plane(struct drm_gem_object *obj) +i915_gem_object_set_to_display_plane(struct drm_gem_object *obj, + bool pipelined) { struct drm_i915_gem_object *obj_priv = to_intel_bo(obj); uint32_t old_read_domains; @@ -2714,8 +2716,8 @@ i915_gem_object_set_to_display_plane(struct drm_gem_object *obj) if (obj_priv->gtt_space == NULL) return -EINVAL; - ret = i915_gem_object_flush_gpu_write_domain(obj, true); - if (ret != 0) + ret = i915_gem_object_flush_gpu_write_domain(obj, pipelined); + if (ret) return ret; i915_gem_object_flush_cpu_write_domain(obj); diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 810ed2d..a7628fd 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -1417,7 +1417,9 @@ out_disable: } int -intel_pin_and_fence_fb_obj(struct drm_device *dev, struct drm_gem_object *obj) +intel_pin_and_fence_fb_obj(struct drm_device *dev, + struct drm_gem_object *obj, + bool pipelined) { struct drm_i915_gem_object *obj_priv = to_intel_bo(obj); u32 alignment; @@ -1445,14 +1447,12 @@ intel_pin_and_fence_fb_obj(struct drm_device *dev, struct drm_gem_object *obj) } ret = i915_gem_object_pin(obj, alignment); - if (ret != 0) + if (ret) return ret; - ret = i915_gem_object_set_to_display_plane(obj); - if (ret != 0) { - i915_gem_object_unpin(obj); - return ret; - } + ret = i915_gem_object_set_to_display_plane(obj, pipelined); + if (ret) + goto err_unpin; /* Install a fence for tiled scan-out. Pre-i965 always needs a * fence, whereas 965+ only requires a fence if using @@ -1462,13 +1462,15 @@ intel_pin_and_fence_fb_obj(struct drm_device *dev, struct drm_gem_object *obj) if (obj_priv->fence_reg == I915_FENCE_REG_NONE && obj_priv->tiling_mode != I915_TILING_NONE) { ret = i915_gem_object_get_fence_reg(obj); - if (ret != 0) { - i915_gem_object_unpin(obj); - return ret; - } + if (ret) + goto err_unpin; } return 0; + +err_unpin: + i915_gem_object_unpin(obj); + return ret; } /* Assume fb object is pinned & idle & fenced and just update base pointers */ @@ -1589,7 +1591,7 @@ intel_pipe_set_base(struct drm_crtc *crtc, int x, int y, obj_priv = to_intel_bo(obj); mutex_lock(&dev->struct_mutex); - ret = intel_pin_and_fence_fb_obj(dev, obj); + ret = intel_pin_and_fence_fb_obj(dev, obj, false); if (ret != 0) { mutex_unlock(&dev->struct_mutex); return ret; @@ -5004,7 +5006,7 @@ static int intel_crtc_page_flip(struct drm_crtc *crtc, struct intel_unpin_work *work; unsigned long flags, offset; int pipe = intel_crtc->pipe; - u32 pf, pipesrc; + u32 was_dirty, pf, pipesrc; int ret; work = kzalloc(sizeof *work, GFP_KERNEL); @@ -5033,7 +5035,8 @@ static int intel_crtc_page_flip(struct drm_crtc *crtc, obj = intel_fb->obj; mutex_lock(&dev->struct_mutex); - ret = intel_pin_and_fence_fb_obj(dev, obj); + was_dirty = obj->write_domain & I915_GEM_GPU_DOMAINS; + ret = intel_pin_and_fence_fb_obj(dev, obj, true); if (ret) goto cleanup_work; @@ -5051,17 +5054,24 @@ static int intel_crtc_page_flip(struct drm_crtc *crtc, atomic_inc(&obj_priv->pending_flip); work->pending_flip_obj = obj; - if (IS_GEN3(dev) || IS_GEN2(dev)) { - u32 flip_mask; + if (was_dirty || IS_GEN3(dev) || IS_GEN2(dev)) { + BEGIN_LP_RING(2); + if (IS_GEN3(dev) || IS_GEN2(dev)) { + u32 flip_mask; - if (intel_crtc->plane) - flip_mask = MI_WAIT_FOR_PLANE_B_FLIP; - else - flip_mask = MI_WAIT_FOR_PLANE_A_FLIP; + /* Can't queue multiple flips, so wait for the previous + * one to finish before executing the next. + */ - BEGIN_LP_RING(2); - OUT_RING(MI_WAIT_FOR_EVENT | flip_mask); - OUT_RING(0); + if (intel_crtc->plane) + flip_mask = MI_WAIT_FOR_PLANE_B_FLIP; + else + flip_mask = MI_WAIT_FOR_PLANE_A_FLIP; + + OUT_RING(MI_WAIT_FOR_EVENT | flip_mask); + } else + OUT_RING(MI_NOOP); + OUT_RING(MI_FLUSH); ADVANCE_LP_RING(); } diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index 5171b05..31f072d 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -281,7 +281,8 @@ extern void ironlake_enable_drps(struct drm_device *dev); extern void ironlake_disable_drps(struct drm_device *dev); extern int intel_pin_and_fence_fb_obj(struct drm_device *dev, - struct drm_gem_object *obj); + struct drm_gem_object *obj, + bool pipelined); extern int intel_framebuffer_init(struct drm_device *dev, struct intel_framebuffer *ifb, diff --git a/drivers/gpu/drm/i915/intel_fb.c b/drivers/gpu/drm/i915/intel_fb.c index e2d13e3..8a23bf7 100644 --- a/drivers/gpu/drm/i915/intel_fb.c +++ b/drivers/gpu/drm/i915/intel_fb.c @@ -94,7 +94,7 @@ static int intelfb_create(struct intel_fbdev *ifbdev, mutex_lock(&dev->struct_mutex); /* Flush everything out, we'll be doing GTT only from now on */ - ret = intel_pin_and_fence_fb_obj(dev, fbo); + ret = intel_pin_and_fence_fb_obj(dev, fbo, false); if (ret) { DRM_ERROR("failed to pin fb: %d\n", ret); goto out_unref; -- cgit v1.1 From 2cf34d7b7ee99c27c1a6bdd2f91344cbfa5fef5c Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Tue, 14 Sep 2010 13:03:28 +0100 Subject: drm/i915: Allow get_fence_reg() to be uninterruptible As we currently may need to acquire a fence register during a modeset, we need to be able to do so in an uninterruptible manner. So expose that parameter to the callers of the fence management code. Signed-off-by: Chris Wilson --- drivers/gpu/drm/i915/i915_drv.h | 6 +++-- drivers/gpu/drm/i915/i915_gem.c | 43 ++++++++++++++++++++-------------- drivers/gpu/drm/i915/i915_gem_tiling.c | 2 +- drivers/gpu/drm/i915/intel_display.c | 2 +- 4 files changed, 31 insertions(+), 22 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index b97d62d..b0692c4 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -986,8 +986,10 @@ void i915_gem_lastclose(struct drm_device *dev); uint32_t i915_get_gem_seqno(struct drm_device *dev, struct intel_ring_buffer *ring); bool i915_seqno_passed(uint32_t seq1, uint32_t seq2); -int i915_gem_object_get_fence_reg(struct drm_gem_object *obj); -int i915_gem_object_put_fence_reg(struct drm_gem_object *obj); +int i915_gem_object_get_fence_reg(struct drm_gem_object *obj, + bool interruptible); +int i915_gem_object_put_fence_reg(struct drm_gem_object *obj, + bool interruptible); void i915_gem_retire_requests(struct drm_device *dev); void i915_gem_clflush_object(struct drm_gem_object *obj); int i915_gem_object_set_domain(struct drm_gem_object *obj, diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index 85a3cf4..02719df 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -48,7 +48,8 @@ static int i915_gem_object_set_cpu_read_domain_range(struct drm_gem_object *obj, uint64_t offset, uint64_t size); static void i915_gem_object_set_to_full_cpu_read_domain(struct drm_gem_object *obj); -static int i915_gem_object_wait_rendering(struct drm_gem_object *obj); +static int i915_gem_object_wait_rendering(struct drm_gem_object *obj, + bool interruptible); static int i915_gem_object_bind_to_gtt(struct drm_gem_object *obj, unsigned alignment); static void i915_gem_clear_fence_reg(struct drm_gem_object *obj); @@ -1181,7 +1182,7 @@ int i915_gem_fault(struct vm_area_struct *vma, struct vm_fault *vmf) /* Need a new fence register? */ if (obj_priv->tiling_mode != I915_TILING_NONE) { - ret = i915_gem_object_get_fence_reg(obj); + ret = i915_gem_object_get_fence_reg(obj, true); if (ret) goto unlock; } @@ -1919,7 +1920,8 @@ i915_gem_flush(struct drm_device *dev, * safe to unbind from the GTT or access from the CPU. */ static int -i915_gem_object_wait_rendering(struct drm_gem_object *obj) +i915_gem_object_wait_rendering(struct drm_gem_object *obj, + bool interruptible) { struct drm_device *dev = obj->dev; struct drm_i915_gem_object *obj_priv = to_intel_bo(obj); @@ -1938,10 +1940,11 @@ i915_gem_object_wait_rendering(struct drm_gem_object *obj) DRM_INFO("%s: object %p wait for seqno %08x\n", __func__, obj, obj_priv->last_rendering_seqno); #endif - ret = i915_wait_request(dev, - obj_priv->last_rendering_seqno, - obj_priv->ring); - if (ret != 0) + ret = i915_do_wait_request(dev, + obj_priv->last_rendering_seqno, + interruptible, + obj_priv->ring); + if (ret) return ret; } @@ -2234,7 +2237,8 @@ static void i830_write_fence_reg(struct drm_i915_fence_reg *reg) I915_WRITE(FENCE_REG_830_0 + (regnum * 4), val); } -static int i915_find_fence_reg(struct drm_device *dev) +static int i915_find_fence_reg(struct drm_device *dev, + bool interruptible) { struct drm_i915_fence_reg *reg = NULL; struct drm_i915_gem_object *obj_priv = NULL; @@ -2279,7 +2283,7 @@ static int i915_find_fence_reg(struct drm_device *dev) * private reference to obj like the other callers of put_fence_reg * (set_tiling ioctl) do. */ drm_gem_object_reference(obj); - ret = i915_gem_object_put_fence_reg(obj); + ret = i915_gem_object_put_fence_reg(obj, interruptible); drm_gem_object_unreference(obj); if (ret != 0) return ret; @@ -2301,7 +2305,8 @@ static int i915_find_fence_reg(struct drm_device *dev) * and tiling format. */ int -i915_gem_object_get_fence_reg(struct drm_gem_object *obj) +i915_gem_object_get_fence_reg(struct drm_gem_object *obj, + bool interruptible) { struct drm_device *dev = obj->dev; struct drm_i915_private *dev_priv = dev->dev_private; @@ -2336,7 +2341,7 @@ i915_gem_object_get_fence_reg(struct drm_gem_object *obj) break; } - ret = i915_find_fence_reg(dev); + ret = i915_find_fence_reg(dev, interruptible); if (ret < 0) return ret; @@ -2403,12 +2408,14 @@ i915_gem_clear_fence_reg(struct drm_gem_object *obj) * i915_gem_object_put_fence_reg - waits on outstanding fenced access * to the buffer to finish, and then resets the fence register. * @obj: tiled object holding a fence register. + * @bool: whether the wait upon the fence is interruptible * * Zeroes out the fence register itself and clears out the associated * data structures in dev_priv and obj_priv. */ int -i915_gem_object_put_fence_reg(struct drm_gem_object *obj) +i915_gem_object_put_fence_reg(struct drm_gem_object *obj, + bool interruptible) { struct drm_device *dev = obj->dev; struct drm_i915_gem_object *obj_priv = to_intel_bo(obj); @@ -2429,11 +2436,11 @@ i915_gem_object_put_fence_reg(struct drm_gem_object *obj) if (!IS_I965G(dev)) { int ret; - ret = i915_gem_object_flush_gpu_write_domain(obj, false); + ret = i915_gem_object_flush_gpu_write_domain(obj, true); if (ret) return ret; - ret = i915_gem_object_wait_rendering(obj); + ret = i915_gem_object_wait_rendering(obj, interruptible); if (ret) return ret; } @@ -2606,7 +2613,7 @@ i915_gem_object_flush_gpu_write_domain(struct drm_gem_object *obj, if (pipelined) return 0; - return i915_gem_object_wait_rendering(obj); + return i915_gem_object_wait_rendering(obj, true); } /** Flushes the GTT write domain for the object if it's dirty. */ @@ -2674,7 +2681,7 @@ i915_gem_object_set_to_gtt_domain(struct drm_gem_object *obj, int write) i915_gem_object_flush_cpu_write_domain(obj); if (write) { - ret = i915_gem_object_wait_rendering(obj); + ret = i915_gem_object_wait_rendering(obj, true); if (ret) return ret; } @@ -2756,7 +2763,7 @@ i915_gem_object_set_to_cpu_domain(struct drm_gem_object *obj, int write) i915_gem_object_set_to_full_cpu_read_domain(obj); if (write) { - ret = i915_gem_object_wait_rendering(obj); + ret = i915_gem_object_wait_rendering(obj, true); if (ret) return ret; } @@ -3125,7 +3132,7 @@ i915_gem_object_pin_and_relocate(struct drm_gem_object *obj, * properly handle blits to/from tiled surfaces. */ if (need_fence) { - ret = i915_gem_object_get_fence_reg(obj); + ret = i915_gem_object_get_fence_reg(obj, false); if (ret != 0) { i915_gem_object_unpin(obj); return ret; diff --git a/drivers/gpu/drm/i915/i915_gem_tiling.c b/drivers/gpu/drm/i915/i915_gem_tiling.c index 3c0859e..caef7ff 100644 --- a/drivers/gpu/drm/i915/i915_gem_tiling.c +++ b/drivers/gpu/drm/i915/i915_gem_tiling.c @@ -328,7 +328,7 @@ i915_gem_set_tiling(struct drm_device *dev, void *data, if (!i915_gem_object_fence_offset_ok(obj, args->tiling_mode)) ret = i915_gem_object_unbind(obj); else if (obj_priv->fence_reg != I915_FENCE_REG_NONE) - ret = i915_gem_object_put_fence_reg(obj); + ret = i915_gem_object_put_fence_reg(obj, true); else i915_gem_release_mmap(obj); diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index a7628fd..11d643a 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -1461,7 +1461,7 @@ intel_pin_and_fence_fb_obj(struct drm_device *dev, */ if (obj_priv->fence_reg == I915_FENCE_REG_NONE && obj_priv->tiling_mode != I915_TILING_NONE) { - ret = i915_gem_object_get_fence_reg(obj); + ret = i915_gem_object_get_fence_reg(obj, false); if (ret) goto err_unpin; } -- cgit v1.1 From 890f3359f7b84d7015104360d647ccac5f515542 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Tue, 14 Sep 2010 16:46:59 +0100 Subject: drm/i915/i2c: Track the parent encoder rather than just the dev The SDVO proxy i2c adapter wants to be able to use information stored in the encoder, so pass that through intel_i2c rather than iterate over all known encoders every time. Signed-off-by: Chris Wilson --- drivers/gpu/drm/i915/intel_crt.c | 9 +++--- drivers/gpu/drm/i915/intel_drv.h | 5 ++-- drivers/gpu/drm/i915/intel_dvo.c | 9 +++--- drivers/gpu/drm/i915/intel_hdmi.c | 18 +++++++----- drivers/gpu/drm/i915/intel_i2c.c | 26 ++++++++++------ drivers/gpu/drm/i915/intel_lvds.c | 3 +- drivers/gpu/drm/i915/intel_sdvo.c | 62 ++++++++++++++++----------------------- 7 files changed, 67 insertions(+), 65 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_crt.c b/drivers/gpu/drm/i915/intel_crt.c index b39183b..0403ec9 100644 --- a/drivers/gpu/drm/i915/intel_crt.c +++ b/drivers/gpu/drm/i915/intel_crt.c @@ -445,19 +445,17 @@ static void intel_crt_destroy(struct drm_connector *connector) static int intel_crt_get_modes(struct drm_connector *connector) { - int ret; struct intel_encoder *encoder = intel_attached_encoder(connector); struct i2c_adapter *ddc_bus; struct drm_device *dev = connector->dev; - + int ret; ret = intel_ddc_get_modes(connector, encoder->ddc_bus); if (ret || !IS_G4X(dev)) goto end; /* Try to probe digital port for output in DVI-I -> VGA mode. */ - ddc_bus = intel_i2c_create(connector->dev, GPIOD, "CRTDDC_D"); - + ddc_bus = intel_i2c_create(encoder, GPIOD, "CRTDDC_D"); if (!ddc_bus) { dev_printk(KERN_ERR, &connector->dev->pdev->dev, "DDC bus registration failed for CRTDDC_D.\n"); @@ -545,7 +543,8 @@ void intel_crt_init(struct drm_device *dev) if (dev_priv->crt_ddc_bus != 0) i2c_reg = dev_priv->crt_ddc_bus; } - intel_encoder->ddc_bus = intel_i2c_create(dev, i2c_reg, "CRTDDC_A"); + intel_encoder->ddc_bus = intel_i2c_create(intel_encoder, + i2c_reg, "CRTDDC_A"); if (!intel_encoder->ddc_bus) { dev_printk(KERN_ERR, &dev->pdev->dev, "DDC bus registration " "failed.\n"); diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index 31f072d..8fe6b73 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -128,7 +128,7 @@ intel_mode_get_pixel_multiplier(const struct drm_display_mode *mode) } struct intel_i2c_chan { - struct drm_device *drm_dev; /* for getting at dev. private (mmio etc.) */ + struct intel_encoder *encoder; u32 reg; /* GPIO reg */ struct i2c_adapter adapter; struct i2c_algo_bit_data algo; @@ -206,7 +206,8 @@ struct intel_unpin_work { bool enable_stall_check; }; -struct i2c_adapter *intel_i2c_create(struct drm_device *dev, const u32 reg, +struct i2c_adapter *intel_i2c_create(struct intel_encoder *encoder, + const u32 reg, const char *name); void intel_i2c_destroy(struct i2c_adapter *adapter); int intel_ddc_get_modes(struct drm_connector *c, struct i2c_adapter *adapter); diff --git a/drivers/gpu/drm/i915/intel_dvo.c b/drivers/gpu/drm/i915/intel_dvo.c index df42a9c..7de7d1a 100644 --- a/drivers/gpu/drm/i915/intel_dvo.c +++ b/drivers/gpu/drm/i915/intel_dvo.c @@ -362,7 +362,8 @@ void intel_dvo_init(struct drm_device *dev) intel_encoder = &intel_dvo->base; /* Set up the DDC bus */ - intel_encoder->ddc_bus = intel_i2c_create(dev, GPIOD, "DVODDC_D"); + intel_encoder->ddc_bus = intel_i2c_create(intel_encoder, + GPIOD, "DVODDC_D"); if (!intel_encoder->ddc_bus) goto free_intel; @@ -389,10 +390,10 @@ void intel_dvo_init(struct drm_device *dev) */ if (i2cbus != NULL) intel_i2c_destroy(i2cbus); - if (!(i2cbus = intel_i2c_create(dev, gpio, - gpio == GPIOB ? "DVOI2C_B" : "DVOI2C_E"))) { + i2cbus = intel_i2c_create(intel_encoder, gpio, + gpio == GPIOB ? "DVOI2C_B" : "DVOI2C_E"); + if (i2cbus == NULL) continue; - } intel_dvo->dev = *dvo; ret = dvo->dev_ops->init(&intel_dvo->dev, i2cbus); diff --git a/drivers/gpu/drm/i915/intel_hdmi.c b/drivers/gpu/drm/i915/intel_hdmi.c index bba0aba..93d5b61 100644 --- a/drivers/gpu/drm/i915/intel_hdmi.c +++ b/drivers/gpu/drm/i915/intel_hdmi.c @@ -243,26 +243,28 @@ void intel_hdmi_init(struct drm_device *dev, int sdvox_reg) /* Set up the DDC bus. */ if (sdvox_reg == SDVOB) { intel_encoder->clone_mask = (1 << INTEL_HDMIB_CLONE_BIT); - intel_encoder->ddc_bus = intel_i2c_create(dev, GPIOE, "HDMIB"); + intel_encoder->ddc_bus = intel_i2c_create(intel_encoder, + GPIOE, "HDMIB"); dev_priv->hotplug_supported_mask |= HDMIB_HOTPLUG_INT_STATUS; } else if (sdvox_reg == SDVOC) { intel_encoder->clone_mask = (1 << INTEL_HDMIC_CLONE_BIT); - intel_encoder->ddc_bus = intel_i2c_create(dev, GPIOD, "HDMIC"); + intel_encoder->ddc_bus = intel_i2c_create(intel_encoder, + GPIOD, "HDMIC"); dev_priv->hotplug_supported_mask |= HDMIC_HOTPLUG_INT_STATUS; } else if (sdvox_reg == HDMIB) { intel_encoder->clone_mask = (1 << INTEL_HDMID_CLONE_BIT); - intel_encoder->ddc_bus = intel_i2c_create(dev, PCH_GPIOE, - "HDMIB"); + intel_encoder->ddc_bus = intel_i2c_create(intel_encoder, + PCH_GPIOE, "HDMIB"); dev_priv->hotplug_supported_mask |= HDMIB_HOTPLUG_INT_STATUS; } else if (sdvox_reg == HDMIC) { intel_encoder->clone_mask = (1 << INTEL_HDMIE_CLONE_BIT); - intel_encoder->ddc_bus = intel_i2c_create(dev, PCH_GPIOD, - "HDMIC"); + intel_encoder->ddc_bus = intel_i2c_create(intel_encoder, + PCH_GPIOD, "HDMIC"); dev_priv->hotplug_supported_mask |= HDMIC_HOTPLUG_INT_STATUS; } else if (sdvox_reg == HDMID) { intel_encoder->clone_mask = (1 << INTEL_HDMIF_CLONE_BIT); - intel_encoder->ddc_bus = intel_i2c_create(dev, PCH_GPIOF, - "HDMID"); + intel_encoder->ddc_bus = intel_i2c_create(intel_encoder, + PCH_GPIOF, "HDMID"); dev_priv->hotplug_supported_mask |= HDMID_HOTPLUG_INT_STATUS; } if (!intel_encoder->ddc_bus) diff --git a/drivers/gpu/drm/i915/intel_i2c.c b/drivers/gpu/drm/i915/intel_i2c.c index de03989..d3d65a9 100644 --- a/drivers/gpu/drm/i915/intel_i2c.c +++ b/drivers/gpu/drm/i915/intel_i2c.c @@ -58,25 +58,31 @@ void intel_i2c_quirk_set(struct drm_device *dev, bool enable) #define I2C_RISEFALL_TIME 20 +static inline struct drm_i915_private * +get_dev_priv(struct intel_i2c_chan *chan) +{ + return chan->encoder->base.dev->dev_private; +} + static int get_clock(void *data) { struct intel_i2c_chan *chan = data; - struct drm_i915_private *dev_priv = chan->drm_dev->dev_private; + struct drm_i915_private *dev_priv = get_dev_priv(chan); return (I915_READ(chan->reg) & GPIO_CLOCK_VAL_IN) != 0; } static int get_data(void *data) { struct intel_i2c_chan *chan = data; - struct drm_i915_private *dev_priv = chan->drm_dev->dev_private; + struct drm_i915_private *dev_priv = get_dev_priv(chan); return (I915_READ(chan->reg) & GPIO_DATA_VAL_IN) != 0; } static void set_clock(void *data, int state_high) { struct intel_i2c_chan *chan = data; - struct drm_device *dev = chan->drm_dev; - struct drm_i915_private *dev_priv = chan->drm_dev->dev_private; + struct drm_i915_private *dev_priv = get_dev_priv(chan); + struct drm_device *dev = dev_priv->dev; u32 reserved = 0, clock_bits; /* On most chips, these bits must be preserved in software. */ @@ -96,8 +102,8 @@ static void set_clock(void *data, int state_high) static void set_data(void *data, int state_high) { struct intel_i2c_chan *chan = data; - struct drm_device *dev = chan->drm_dev; - struct drm_i915_private *dev_priv = chan->drm_dev->dev_private; + struct drm_i915_private *dev_priv = get_dev_priv(chan); + struct drm_device *dev = dev_priv->dev; u32 reserved = 0, data_bits; /* On most chips, these bits must be preserved in software. */ @@ -153,16 +159,18 @@ intel_i2c_reset_gmbus(struct drm_device *dev) * %GPIOH * see PRM for details on how these different busses are used. */ -struct i2c_adapter *intel_i2c_create(struct drm_device *dev, const u32 reg, +struct i2c_adapter *intel_i2c_create(struct intel_encoder *encoder, + const u32 reg, const char *name) { struct intel_i2c_chan *chan; + struct drm_device *dev = encoder->base.dev; chan = kzalloc(sizeof(struct intel_i2c_chan), GFP_KERNEL); if (!chan) goto out_free; - chan->drm_dev = dev; + chan->encoder = encoder; chan->reg = reg; snprintf(chan->adapter.name, I2C_NAME_SIZE, "intel drm %s", name); chan->adapter.owner = THIS_MODULE; @@ -178,7 +186,7 @@ struct i2c_adapter *intel_i2c_create(struct drm_device *dev, const u32 reg, i2c_set_adapdata(&chan->adapter, chan); - if(i2c_bit_add_bus(&chan->adapter)) + if (i2c_bit_add_bus(&chan->adapter)) goto out_free; intel_i2c_reset_gmbus(dev); diff --git a/drivers/gpu/drm/i915/intel_lvds.c b/drivers/gpu/drm/i915/intel_lvds.c index b56b592..2ff4a5cb 100644 --- a/drivers/gpu/drm/i915/intel_lvds.c +++ b/drivers/gpu/drm/i915/intel_lvds.c @@ -899,7 +899,8 @@ void intel_lvds_init(struct drm_device *dev) */ /* Set up the DDC bus. */ - intel_encoder->ddc_bus = intel_i2c_create(dev, gpio, "LVDSDDC_C"); + intel_encoder->ddc_bus = intel_i2c_create(intel_encoder, + gpio, "LVDSDDC_C"); if (!intel_encoder->ddc_bus) { dev_printk(KERN_ERR, &dev->pdev->dev, "DDC bus registration " "failed.\n"); diff --git a/drivers/gpu/drm/i915/intel_sdvo.c b/drivers/gpu/drm/i915/intel_sdvo.c index a812d65..0e68f96 100644 --- a/drivers/gpu/drm/i915/intel_sdvo.c +++ b/drivers/gpu/drm/i915/intel_sdvo.c @@ -184,7 +184,7 @@ struct intel_sdvo_connector { u32 cur_dot_crawl, max_dot_crawl; }; -static struct intel_sdvo *enc_to_intel_sdvo(struct drm_encoder *encoder) +static struct intel_sdvo *to_intel_sdvo(struct drm_encoder *encoder) { return container_of(encoder, struct intel_sdvo, base.base); } @@ -1051,7 +1051,7 @@ static bool intel_sdvo_mode_fixup(struct drm_encoder *encoder, struct drm_display_mode *mode, struct drm_display_mode *adjusted_mode) { - struct intel_sdvo *intel_sdvo = enc_to_intel_sdvo(encoder); + struct intel_sdvo *intel_sdvo = to_intel_sdvo(encoder); int multiplier; /* We need to construct preferred input timings based on our @@ -1093,7 +1093,7 @@ static void intel_sdvo_mode_set(struct drm_encoder *encoder, struct drm_i915_private *dev_priv = dev->dev_private; struct drm_crtc *crtc = encoder->crtc; struct intel_crtc *intel_crtc = to_intel_crtc(crtc); - struct intel_sdvo *intel_sdvo = enc_to_intel_sdvo(encoder); + struct intel_sdvo *intel_sdvo = to_intel_sdvo(encoder); u32 sdvox; struct intel_sdvo_in_out_map in_out; struct intel_sdvo_dtd input_dtd; @@ -1200,7 +1200,7 @@ static void intel_sdvo_dpms(struct drm_encoder *encoder, int mode) { struct drm_device *dev = encoder->dev; struct drm_i915_private *dev_priv = dev->dev_private; - struct intel_sdvo *intel_sdvo = enc_to_intel_sdvo(encoder); + struct intel_sdvo *intel_sdvo = to_intel_sdvo(encoder); struct intel_crtc *intel_crtc = to_intel_crtc(encoder->crtc); u32 temp; @@ -1899,7 +1899,7 @@ static const struct drm_connector_helper_funcs intel_sdvo_connector_helper_funcs static void intel_sdvo_enc_destroy(struct drm_encoder *encoder) { - struct intel_sdvo *intel_sdvo = enc_to_intel_sdvo(encoder); + struct intel_sdvo *intel_sdvo = to_intel_sdvo(encoder); if (intel_sdvo->analog_ddc_bus) intel_i2c_destroy(intel_sdvo->analog_ddc_bus); @@ -1984,35 +1984,15 @@ intel_sdvo_get_digital_encoding_mode(struct intel_sdvo *intel_sdvo, int device) &intel_sdvo->is_hdmi, 1); } -static struct intel_sdvo * -intel_sdvo_chan_to_intel_sdvo(struct intel_i2c_chan *chan) -{ - struct drm_device *dev = chan->drm_dev; - struct drm_encoder *encoder; - - list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) { - struct intel_sdvo *intel_sdvo = enc_to_intel_sdvo(encoder); - if (intel_sdvo->base.ddc_bus == &chan->adapter) - return intel_sdvo; - } - - return NULL; -} - static int intel_sdvo_master_xfer(struct i2c_adapter *i2c_adap, struct i2c_msg msgs[], int num) { struct intel_sdvo *intel_sdvo; - struct i2c_algo_bit_data *algo_data; const struct i2c_algorithm *algo; - algo_data = (struct i2c_algo_bit_data *)i2c_adap->algo_data; - intel_sdvo = - intel_sdvo_chan_to_intel_sdvo((struct intel_i2c_chan *) - (algo_data->data)); - if (intel_sdvo == NULL) - return -EINVAL; - + intel_sdvo = container_of(i2c_adap->algo_data, + struct intel_sdvo, + base); algo = intel_sdvo->base.i2c_bus->algo; intel_sdvo_set_control_bus_switch(intel_sdvo, intel_sdvo->ddc_bus); @@ -2560,9 +2540,13 @@ bool intel_sdvo_init(struct drm_device *dev, int sdvo_reg) /* setup the DDC bus. */ if (IS_SDVOB(sdvo_reg)) - intel_encoder->i2c_bus = intel_i2c_create(dev, i2c_reg, "SDVOCTRL_E for SDVOB"); + intel_encoder->i2c_bus = + intel_i2c_create(intel_encoder, + i2c_reg, "SDVOCTRL_E for SDVOB"); else - intel_encoder->i2c_bus = intel_i2c_create(dev, i2c_reg, "SDVOCTRL_E for SDVOC"); + intel_encoder->i2c_bus = + intel_i2c_create(intel_encoder, + i2c_reg, "SDVOCTRL_E for SDVOC"); if (!intel_encoder->i2c_bus) goto err_inteloutput; @@ -2583,14 +2567,20 @@ bool intel_sdvo_init(struct drm_device *dev, int sdvo_reg) /* setup the DDC bus. */ if (IS_SDVOB(sdvo_reg)) { - intel_encoder->ddc_bus = intel_i2c_create(dev, ddc_reg, "SDVOB DDC BUS"); - intel_sdvo->analog_ddc_bus = intel_i2c_create(dev, analog_ddc_reg, - "SDVOB/VGA DDC BUS"); + intel_encoder->ddc_bus = + intel_i2c_create(intel_encoder, + ddc_reg, "SDVOB DDC BUS"); + intel_sdvo->analog_ddc_bus = + intel_i2c_create(intel_encoder, + analog_ddc_reg, "SDVOB/VGA DDC BUS"); dev_priv->hotplug_supported_mask |= SDVOB_HOTPLUG_INT_STATUS; } else { - intel_encoder->ddc_bus = intel_i2c_create(dev, ddc_reg, "SDVOC DDC BUS"); - intel_sdvo->analog_ddc_bus = intel_i2c_create(dev, analog_ddc_reg, - "SDVOC/VGA DDC BUS"); + intel_encoder->ddc_bus = + intel_i2c_create(intel_encoder, + ddc_reg, "SDVOC DDC BUS"); + intel_sdvo->analog_ddc_bus = + intel_i2c_create(intel_encoder, + analog_ddc_reg, "SDVOC/VGA DDC BUS"); dev_priv->hotplug_supported_mask |= SDVOC_HOTPLUG_INT_STATUS; } if (intel_encoder->ddc_bus == NULL || intel_sdvo->analog_ddc_bus == NULL) -- cgit v1.1 From 2b6efaa47615b29e572d7fc444565db62ca9bcf7 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Tue, 14 Sep 2010 17:04:02 +0100 Subject: drm/i915: Remove unused intel_ringbuffer->ring_flag This can always be re-added should somebody find a use... Signed-off-by: Chris Wilson --- drivers/gpu/drm/i915/i915_gem.c | 5 ++--- drivers/gpu/drm/i915/intel_ringbuffer.c | 2 -- drivers/gpu/drm/i915/intel_ringbuffer.h | 1 - 3 files changed, 2 insertions(+), 6 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index 02719df..a83574d 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -1580,9 +1580,8 @@ i915_gem_process_flushing_list(struct drm_device *dev, gpu_write_list) { struct drm_gem_object *obj = &obj_priv->base; - if ((obj->write_domain & flush_domains) == - obj->write_domain && - obj_priv->ring->ring_flag == ring->ring_flag) { + if (obj->write_domain & flush_domains && + obj_priv->ring == ring) { uint32_t old_write_domain = obj->write_domain; obj->write_domain = 0; diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.c b/drivers/gpu/drm/i915/intel_ringbuffer.c index 1ae2b25..11bcfc8 100644 --- a/drivers/gpu/drm/i915/intel_ringbuffer.c +++ b/drivers/gpu/drm/i915/intel_ringbuffer.c @@ -805,7 +805,6 @@ struct intel_ring_buffer render_ring = { .tail = PRB0_TAIL, .start = PRB0_START }, - .ring_flag = I915_EXEC_RENDER, .size = 32 * PAGE_SIZE, .alignment = PAGE_SIZE, .virtual_start = NULL, @@ -843,7 +842,6 @@ struct intel_ring_buffer bsd_ring = { .tail = BSD_RING_TAIL, .start = BSD_RING_START }, - .ring_flag = I915_EXEC_BSD, .size = 32 * PAGE_SIZE, .alignment = PAGE_SIZE, .virtual_start = NULL, diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.h b/drivers/gpu/drm/i915/intel_ringbuffer.h index d3e5f40..fa5d84f 100644 --- a/drivers/gpu/drm/i915/intel_ringbuffer.h +++ b/drivers/gpu/drm/i915/intel_ringbuffer.h @@ -16,7 +16,6 @@ struct intel_ring_buffer { u32 tail; u32 start; } regs; - unsigned int ring_flag; unsigned long size; unsigned int alignment; void *virtual_start; -- cgit v1.1 From 9d1a903d4ba1033b811ded8d3e5d0f01eeeaaa1d Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Tue, 14 Sep 2010 17:58:19 +0100 Subject: drm/i915/sdvo: Tidy intel_sdvo_hdmi_sink_detect Signed-off-by: Chris Wilson --- drivers/gpu/drm/i915/intel_sdvo.c | 55 +++++++++++++++++---------------------- 1 file changed, 24 insertions(+), 31 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_sdvo.c b/drivers/gpu/drm/i915/intel_sdvo.c index 0e68f96..05f5313 100644 --- a/drivers/gpu/drm/i915/intel_sdvo.c +++ b/drivers/gpu/drm/i915/intel_sdvo.c @@ -1417,60 +1417,53 @@ enum drm_connector_status intel_sdvo_hdmi_sink_detect(struct drm_connector *connector) { struct intel_sdvo *intel_sdvo = intel_attached_sdvo(connector); - struct intel_sdvo_connector *intel_sdvo_connector = to_intel_sdvo_connector(connector); - enum drm_connector_status status = connector_status_connected; - struct edid *edid = NULL; + enum drm_connector_status status; + struct edid *edid; edid = drm_get_edid(connector, intel_sdvo->base.ddc_bus); - /* This is only applied to SDVO cards with multiple outputs */ if (edid == NULL && intel_sdvo_multifunc_encoder(intel_sdvo)) { - uint8_t saved_ddc, temp_ddc; - saved_ddc = intel_sdvo->ddc_bus; - temp_ddc = intel_sdvo->ddc_bus >> 1; + u8 saved_ddc = intel_sdvo->ddc_bus, ddc; + /* * Don't use the 1 as the argument of DDC bus switch to get * the EDID. It is used for SDVO SPD ROM. */ - while(temp_ddc > 1) { - intel_sdvo->ddc_bus = temp_ddc; + for (ddc = intel_sdvo->ddc_bus >> 1; ddc > 1; ddc >>= 1) { + intel_sdvo->ddc_bus = ddc; edid = drm_get_edid(connector, intel_sdvo->base.ddc_bus); - if (edid) { - /* - * When we can get the EDID, maybe it is the - * correct DDC bus. Update it. - */ - intel_sdvo->ddc_bus = temp_ddc; + if (edid) break; - } - temp_ddc >>= 1; } + + /* + * If we found the EDID on the other bus, maybe that is the + * correct DDC bus. + */ if (edid == NULL) intel_sdvo->ddc_bus = saved_ddc; } - /* when there is no edid and no monitor is connected with VGA - * port, try to use the CRT ddc to read the EDID for DVI-connector + + /* + * When there is no edid and no monitor is connected with VGA + * port, try to use the CRT ddc to read the EDID for DVI-connector. */ - if (edid == NULL && intel_sdvo->analog_ddc_bus && + if (edid == NULL && + intel_sdvo->analog_ddc_bus && !intel_analog_is_connected(connector->dev)) edid = drm_get_edid(connector, intel_sdvo->analog_ddc_bus); + status = connector_status_disconnected; if (edid != NULL) { - bool is_digital = !!(edid->input & DRM_EDID_INPUT_DIGITAL); - bool need_digital = !!(intel_sdvo_connector->output_flag & SDVO_TMDS_MASK); - /* DDC bus is shared, match EDID to connector type */ - if (is_digital && need_digital) + if (edid->input & DRM_EDID_INPUT_DIGITAL) { + status = connector_status_connected; intel_sdvo->is_hdmi = drm_detect_hdmi_monitor(edid); - else if (is_digital != need_digital) - status = connector_status_disconnected; - + } connector->display_info.raw_edid = NULL; - } else - status = connector_status_disconnected; + kfree(edid); + } - kfree(edid); - return status; } -- cgit v1.1 From 819f3fb7fe349d0e6aadbd7088529ab95fe5cd9f Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Tue, 14 Sep 2010 19:11:56 +0100 Subject: drm/i915/sdvo: Propagate i2c error from switching DDC control bus. Signed-off-by: Chris Wilson --- drivers/gpu/drm/i915/intel_sdvo.c | 27 ++++++++++++++++++--------- 1 file changed, 18 insertions(+), 9 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_sdvo.c b/drivers/gpu/drm/i915/intel_sdvo.c index 05f5313..fa9dbb7 100644 --- a/drivers/gpu/drm/i915/intel_sdvo.c +++ b/drivers/gpu/drm/i915/intel_sdvo.c @@ -530,8 +530,8 @@ static int intel_sdvo_get_pixel_multiplier(struct drm_display_mode *mode) * another I2C transaction after issuing the DDC bus switch, it will be * switched to the internal SDVO register. */ -static void intel_sdvo_set_control_bus_switch(struct intel_sdvo *intel_sdvo, - u8 target) +static int intel_sdvo_set_control_bus_switch(struct intel_sdvo *intel_sdvo, + u8 target) { u8 out_buf[2], cmd_buf[2], ret_value[2], ret; struct i2c_msg msgs[] = { @@ -557,9 +557,10 @@ static void intel_sdvo_set_control_bus_switch(struct intel_sdvo *intel_sdvo, }; intel_sdvo_debug_write(intel_sdvo, SDVO_CMD_SET_CONTROL_BUS_SWITCH, - &target, 1); + &target, 1); /* write the DDC switch command argument */ - intel_sdvo_write_byte(intel_sdvo, SDVO_I2C_ARG_0, target); + if (!intel_sdvo_write_byte(intel_sdvo, SDVO_I2C_ARG_0, target)) + return -EIO; out_buf[0] = SDVO_I2C_OPCODE; out_buf[1] = SDVO_CMD_SET_CONTROL_BUS_SWITCH; @@ -569,17 +570,20 @@ static void intel_sdvo_set_control_bus_switch(struct intel_sdvo *intel_sdvo, ret_value[1] = 0; ret = i2c_transfer(intel_sdvo->base.i2c_bus, msgs, 3); + if (ret < 0) + return ret; if (ret != 3) { /* failure in I2C transfer */ DRM_DEBUG_KMS("I2c transfer returned %d\n", ret); - return; + return -EIO; } if (ret_value[0] != SDVO_CMD_STATUS_SUCCESS) { DRM_DEBUG_KMS("DDC switch command returns response %d\n", - ret_value[0]); - return; + ret_value[0]); + return -EIO; } - return; + + return 0; } static bool intel_sdvo_set_value(struct intel_sdvo *intel_sdvo, u8 cmd, const void *data, int len) @@ -1982,13 +1986,18 @@ static int intel_sdvo_master_xfer(struct i2c_adapter *i2c_adap, { struct intel_sdvo *intel_sdvo; const struct i2c_algorithm *algo; + int ret; intel_sdvo = container_of(i2c_adap->algo_data, struct intel_sdvo, base); algo = intel_sdvo->base.i2c_bus->algo; - intel_sdvo_set_control_bus_switch(intel_sdvo, intel_sdvo->ddc_bus); + ret = intel_sdvo_set_control_bus_switch(intel_sdvo, + intel_sdvo->ddc_bus); + if (ret) + return ret; + return algo->master_xfer(i2c_adap, msgs, num); } -- cgit v1.1 From b1c5b0f8cc16a1d22e2e521c4236a6ceca1b2983 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Tue, 14 Sep 2010 19:30:13 +0100 Subject: agp/intel: Remove redundant setting of gtt_mappable_entries Two calls enter, only one will leave. Signed-off-by: Chris Wilson --- drivers/char/agp/intel-gtt.c | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) diff --git a/drivers/char/agp/intel-gtt.c b/drivers/char/agp/intel-gtt.c index dedf05d..791582c 100644 --- a/drivers/char/agp/intel-gtt.c +++ b/drivers/char/agp/intel-gtt.c @@ -774,18 +774,17 @@ static unsigned int intel_gtt_total_entries(void) static unsigned int intel_gtt_mappable_entries(void) { unsigned int aperture_size; - u16 gmch_ctrl; - aperture_size = 1024 * 1024; + if (INTEL_GTT_GEN == 2) { + u16 gmch_ctrl; - pci_read_config_word(intel_private.bridge_dev, - I830_GMCH_CTRL, &gmch_ctrl); + pci_read_config_word(intel_private.bridge_dev, + I830_GMCH_CTRL, &gmch_ctrl); - if (INTEL_GTT_GEN == 2) { if ((gmch_ctrl & I830_GMCH_MEM_MASK) == I830_GMCH_MEM_64M) - aperture_size *= 64; + aperture_size = MB(64); else - aperture_size *= 128; + aperture_size = MB(128); } else { /* 9xx supports large sizes, just look at the length */ aperture_size = pci_resource_len(intel_private.pcidev, 2); @@ -799,8 +798,6 @@ static int intel_gtt_init(void) u32 gtt_map_size; int ret; - intel_private.base.gtt_mappable_entries = intel_gtt_mappable_entries(); - ret = intel_private.driver->setup(); if (ret != 0) return ret; -- cgit v1.1 From 3f08e4ef807c3103ceebf7993c7463c7a90646f3 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Tue, 14 Sep 2010 20:15:22 +0100 Subject: agp/intel: Fix resume regression from 2d2430cf On i915 [EeePCs] something scribles over the registers during suspend and resume so we must save a copy of the PGETBL_CTL register programmed by the BIOS and restore that upon resume. Reported-by: Sitsofe Wheeler Signed-off-by: Chris Wilson --- drivers/char/agp/intel-gtt.c | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/drivers/char/agp/intel-gtt.c b/drivers/char/agp/intel-gtt.c index 791582c..ebdeab2 100644 --- a/drivers/char/agp/intel-gtt.c +++ b/drivers/char/agp/intel-gtt.c @@ -98,6 +98,7 @@ static struct _intel_private { u8 __iomem *registers; phys_addr_t gtt_bus_addr; phys_addr_t gma_bus_addr; + phys_addr_t pte_bus_addr; u32 __iomem *gtt; /* I915G */ int num_dcache_entries; union { @@ -896,11 +897,9 @@ static void intel_i830_chipset_flush(struct agp_bridge_data *bridge) static void intel_enable_gtt(void) { - u32 ptetbl_addr, gma_addr; + u32 gma_addr; u16 gmch_ctrl; - ptetbl_addr = readl(intel_private.registers+I810_PGETBL_CTL) & 0xfffff000; - if (INTEL_GTT_GEN == 2) pci_read_config_dword(intel_private.pcidev, I810_GMADDR, &gma_addr); @@ -914,7 +913,8 @@ static void intel_enable_gtt(void) gmch_ctrl |= I830_GMCH_ENABLED; pci_write_config_word(intel_private.bridge_dev, I830_GMCH_CTRL, gmch_ctrl); - writel(ptetbl_addr|I810_PGETBL_ENABLED, intel_private.registers+I810_PGETBL_CTL); + writel(intel_private.pte_bus_addr|I810_PGETBL_ENABLED, + intel_private.registers+I810_PGETBL_CTL); readl(intel_private.registers+I810_PGETBL_CTL); /* PCI Posting. */ } @@ -930,6 +930,8 @@ static int i830_setup(void) return -ENOMEM; intel_private.gtt_bus_addr = reg_addr + I810_PTE_BASE; + intel_private.pte_bus_addr = + readl(intel_private.registers+I810_PGETBL_CTL) & 0xfffff000; intel_i830_setup_flush(); @@ -1279,6 +1281,7 @@ static int i9xx_setup(void) if (INTEL_GTT_GEN == 3) { u32 gtt_addr; + pci_read_config_dword(intel_private.pcidev, I915_PTEADDR, >t_addr); intel_private.gtt_bus_addr = gtt_addr; @@ -1298,6 +1301,9 @@ static int i9xx_setup(void) intel_private.gtt_bus_addr = reg_addr + gtt_offset; } + intel_private.pte_bus_addr = + readl(intel_private.registers+I810_PGETBL_CTL) & 0xfffff000; + intel_i9xx_setup_flush(); return 0; -- cgit v1.1 From ff482d8317736908e1f803ef94ee5c736a3b8a3a Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Wed, 15 Sep 2010 10:40:38 +0100 Subject: drm/i915/sdvo: Only create the analog encoder as required We only need to use the analog encoder for rare devices which share the DDC between the DVI-I and VGA connectors, so only create as needed. Signed-off-by: Chris Wilson --- drivers/gpu/drm/i915/intel_sdvo.c | 69 +++++++++++++++++++++++---------------- 1 file changed, 41 insertions(+), 28 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_sdvo.c b/drivers/gpu/drm/i915/intel_sdvo.c index fa9dbb7..fbdae4d 100644 --- a/drivers/gpu/drm/i915/intel_sdvo.c +++ b/drivers/gpu/drm/i915/intel_sdvo.c @@ -125,9 +125,6 @@ struct intel_sdvo { /* DDC bus used by this SDVO encoder */ uint8_t ddc_bus; - /* Mac mini hack -- use the same DDC as the analog connector */ - struct i2c_adapter *analog_ddc_bus; - /* Input timings for adjusted_mode */ struct intel_sdvo_dtd input_dtd; }; @@ -1417,6 +1414,34 @@ intel_analog_is_connected(struct drm_device *dev) return true; } +/* Mac mini hack -- use the same DDC as the analog connector */ +static struct edid * +intel_sdvo_get_analog_edid(struct drm_connector *connector) +{ + struct intel_encoder *encoder = intel_attached_encoder(connector); + struct drm_device *dev = connector->dev; + struct i2c_adapter *ddc; + struct edid *edid; + u32 ddc_reg; + + if (!intel_analog_is_connected(dev)) + return NULL; + + if (HAS_PCH_SPLIT(dev)) + ddc_reg = PCH_GPIOA; + else + ddc_reg = GPIOA; + + ddc = intel_i2c_create(encoder, ddc_reg, "SDVO/VGA DDC BUS"); + if (ddc == NULL) + return NULL; + + edid = drm_get_edid(connector, ddc); + intel_i2c_destroy(ddc); + + return edid; +} + enum drm_connector_status intel_sdvo_hdmi_sink_detect(struct drm_connector *connector) { @@ -1452,10 +1477,8 @@ intel_sdvo_hdmi_sink_detect(struct drm_connector *connector) * When there is no edid and no monitor is connected with VGA * port, try to use the CRT ddc to read the EDID for DVI-connector. */ - if (edid == NULL && - intel_sdvo->analog_ddc_bus && - !intel_analog_is_connected(connector->dev)) - edid = drm_get_edid(connector, intel_sdvo->analog_ddc_bus); + if (edid == NULL) + edid = intel_sdvo_get_analog_edid(connector); status = connector_status_disconnected; if (edid != NULL) { @@ -1522,10 +1545,13 @@ static enum drm_connector_status intel_sdvo_detect(struct drm_connector *connect static void intel_sdvo_get_ddc_modes(struct drm_connector *connector) { struct intel_sdvo *intel_sdvo = intel_attached_sdvo(connector); + struct edid *edid; int num_modes; /* set the bus switch and get the modes */ num_modes = intel_ddc_get_modes(connector, intel_sdvo->base.ddc_bus); + if (num_modes) + return; /* * Mac mini hack. On this device, the DVI-I connector shares one DDC @@ -1533,12 +1559,12 @@ static void intel_sdvo_get_ddc_modes(struct drm_connector *connector) * DDC fails, check to see if the analog output is disconnected, in * which case we'll look there for the digital DDC data. */ - if (num_modes == 0 && - intel_sdvo->analog_ddc_bus && - !intel_analog_is_connected(connector->dev)) { - /* Switch to the analog ddc bus and try that - */ - (void) intel_ddc_get_modes(connector, intel_sdvo->analog_ddc_bus); + edid = intel_sdvo_get_analog_edid(connector); + if (edid != NULL) { + drm_mode_connector_update_edid_property(connector, edid); + drm_add_edid_modes(connector, edid); + connector->display_info.raw_edid = NULL; + kfree(edid); } } @@ -1898,9 +1924,6 @@ static void intel_sdvo_enc_destroy(struct drm_encoder *encoder) { struct intel_sdvo *intel_sdvo = to_intel_sdvo(encoder); - if (intel_sdvo->analog_ddc_bus) - intel_i2c_destroy(intel_sdvo->analog_ddc_bus); - if (intel_sdvo->sdvo_lvds_fixed_mode != NULL) drm_mode_destroy(encoder->dev, intel_sdvo->sdvo_lvds_fixed_mode); @@ -2519,7 +2542,7 @@ bool intel_sdvo_init(struct drm_device *dev, int sdvo_reg) struct intel_sdvo *intel_sdvo; u8 ch[0x40]; int i; - u32 i2c_reg, ddc_reg, analog_ddc_reg; + u32 i2c_reg, ddc_reg; intel_sdvo = kzalloc(sizeof(struct intel_sdvo), GFP_KERNEL); if (!intel_sdvo) @@ -2533,11 +2556,9 @@ bool intel_sdvo_init(struct drm_device *dev, int sdvo_reg) if (HAS_PCH_SPLIT(dev)) { i2c_reg = PCH_GPIOE; ddc_reg = PCH_GPIOE; - analog_ddc_reg = PCH_GPIOA; } else { i2c_reg = GPIOE; ddc_reg = GPIOE; - analog_ddc_reg = GPIOA; } /* setup the DDC bus. */ @@ -2572,20 +2593,14 @@ bool intel_sdvo_init(struct drm_device *dev, int sdvo_reg) intel_encoder->ddc_bus = intel_i2c_create(intel_encoder, ddc_reg, "SDVOB DDC BUS"); - intel_sdvo->analog_ddc_bus = - intel_i2c_create(intel_encoder, - analog_ddc_reg, "SDVOB/VGA DDC BUS"); dev_priv->hotplug_supported_mask |= SDVOB_HOTPLUG_INT_STATUS; } else { intel_encoder->ddc_bus = intel_i2c_create(intel_encoder, ddc_reg, "SDVOC DDC BUS"); - intel_sdvo->analog_ddc_bus = - intel_i2c_create(intel_encoder, - analog_ddc_reg, "SDVOC/VGA DDC BUS"); dev_priv->hotplug_supported_mask |= SDVOC_HOTPLUG_INT_STATUS; } - if (intel_encoder->ddc_bus == NULL || intel_sdvo->analog_ddc_bus == NULL) + if (intel_encoder->ddc_bus == NULL) goto err_i2c; /* Wrap with our custom algo which switches to DDC mode */ @@ -2638,8 +2653,6 @@ bool intel_sdvo_init(struct drm_device *dev, int sdvo_reg) err_enc: drm_encoder_cleanup(&intel_encoder->base); err_i2c: - if (intel_sdvo->analog_ddc_bus != NULL) - intel_i2c_destroy(intel_sdvo->analog_ddc_bus); if (intel_encoder->ddc_bus != NULL) intel_i2c_destroy(intel_encoder->ddc_bus); if (intel_encoder->i2c_bus != NULL) -- cgit v1.1 From 2f551c84563df2bf144a819993b2d729c66583ee Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Wed, 15 Sep 2010 10:42:50 +0100 Subject: drm/i915/sdvo: Mark the status as unknown if attached with EDID One problem with devices that share the DDC bus between the VGA and DVI-I connectors is that with two devices attached we cannot know if there is truly a monitor attached to the DVI connector. In this case, it is preferrrable to mark the status as unknown, so that the user can supply the known set of modes and continue to use the output. Signed-off-by: Chris Wilson --- 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 fbdae4d..d2b4a6a 100644 --- a/drivers/gpu/drm/i915/intel_sdvo.c +++ b/drivers/gpu/drm/i915/intel_sdvo.c @@ -1480,7 +1480,7 @@ intel_sdvo_hdmi_sink_detect(struct drm_connector *connector) if (edid == NULL) edid = intel_sdvo_get_analog_edid(connector); - status = connector_status_disconnected; + status = connector_status_unknown; if (edid != NULL) { /* DDC bus is shared, match EDID to connector type */ if (edid->input & DRM_EDID_INPUT_DIGITAL) { -- cgit v1.1 From 373a3cf744c774478f44921c50011b896ab08f9d Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Wed, 15 Sep 2010 12:03:59 +0100 Subject: drm/i915: call drm_encoder_init first Later initialisation of the encoder often requires that drm_encoder_init() has already been called, for instance, initialiasing the DDC buses. Yet another recent regression, as 819f3fb7 depended upon these fixes which I missed when cherry-picking. Signed-off-by: Chris Wilson --- drivers/gpu/drm/i915/intel_crt.c | 4 ++++ drivers/gpu/drm/i915/intel_dvo.c | 5 +++-- drivers/gpu/drm/i915/intel_hdmi.c | 6 ++++-- drivers/gpu/drm/i915/intel_sdvo.c | 15 +++++++-------- 4 files changed, 18 insertions(+), 12 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_crt.c b/drivers/gpu/drm/i915/intel_crt.c index 0403ec9..2353da6 100644 --- a/drivers/gpu/drm/i915/intel_crt.c +++ b/drivers/gpu/drm/i915/intel_crt.c @@ -548,6 +548,10 @@ void intel_crt_init(struct drm_device *dev) if (!intel_encoder->ddc_bus) { dev_printk(KERN_ERR, &dev->pdev->dev, "DDC bus registration " "failed.\n"); + drm_connector_cleanup(&intel_connector->base); + kfree(intel_connector); + drm_encoder_cleanup(&intel_encoder->base); + kfree(intel_encoder); return; } diff --git a/drivers/gpu/drm/i915/intel_dvo.c b/drivers/gpu/drm/i915/intel_dvo.c index 7de7d1a..d8a586b 100644 --- a/drivers/gpu/drm/i915/intel_dvo.c +++ b/drivers/gpu/drm/i915/intel_dvo.c @@ -360,6 +360,8 @@ void intel_dvo_init(struct drm_device *dev) } intel_encoder = &intel_dvo->base; + drm_encoder_init(dev, &intel_encoder->base, + &intel_dvo_enc_funcs, encoder_type); /* Set up the DDC bus */ intel_encoder->ddc_bus = intel_i2c_create(intel_encoder, @@ -428,8 +430,6 @@ void intel_dvo_init(struct drm_device *dev) connector->interlace_allowed = false; connector->doublescan_allowed = false; - drm_encoder_init(dev, &intel_encoder->base, - &intel_dvo_enc_funcs, encoder_type); drm_encoder_helper_add(&intel_encoder->base, &intel_dvo_helper_funcs); @@ -456,6 +456,7 @@ void intel_dvo_init(struct drm_device *dev) if (i2cbus != NULL) intel_i2c_destroy(i2cbus); free_intel: + drm_encoder_cleanup(&intel_encoder->base); kfree(intel_dvo); kfree(intel_connector); } diff --git a/drivers/gpu/drm/i915/intel_hdmi.c b/drivers/gpu/drm/i915/intel_hdmi.c index 93d5b61..783924c 100644 --- a/drivers/gpu/drm/i915/intel_hdmi.c +++ b/drivers/gpu/drm/i915/intel_hdmi.c @@ -228,6 +228,9 @@ void intel_hdmi_init(struct drm_device *dev, int sdvox_reg) } intel_encoder = &intel_hdmi->base; + drm_encoder_init(dev, &intel_encoder->base, &intel_hdmi_enc_funcs, + DRM_MODE_ENCODER_TMDS); + connector = &intel_connector->base; drm_connector_init(dev, connector, &intel_hdmi_connector_funcs, DRM_MODE_CONNECTOR_HDMIA); @@ -272,8 +275,6 @@ void intel_hdmi_init(struct drm_device *dev, int sdvox_reg) intel_hdmi->sdvox_reg = sdvox_reg; - drm_encoder_init(dev, &intel_encoder->base, &intel_hdmi_enc_funcs, - DRM_MODE_ENCODER_TMDS); drm_encoder_helper_add(&intel_encoder->base, &intel_hdmi_helper_funcs); intel_connector_attach_encoder(intel_connector, intel_encoder); @@ -291,6 +292,7 @@ void intel_hdmi_init(struct drm_device *dev, int sdvox_reg) return; err_connector: + drm_encoder_cleanup(&intel_encoder->base); drm_connector_cleanup(connector); kfree(intel_hdmi); kfree(intel_connector); diff --git a/drivers/gpu/drm/i915/intel_sdvo.c b/drivers/gpu/drm/i915/intel_sdvo.c index d2b4a6a..f7030e4 100644 --- a/drivers/gpu/drm/i915/intel_sdvo.c +++ b/drivers/gpu/drm/i915/intel_sdvo.c @@ -2552,6 +2552,8 @@ bool intel_sdvo_init(struct drm_device *dev, int sdvo_reg) intel_encoder = &intel_sdvo->base; intel_encoder->type = INTEL_OUTPUT_SDVO; + /* encoder type will be decided later */ + drm_encoder_init(dev, &intel_encoder->base, &intel_sdvo_enc_funcs, 0); if (HAS_PCH_SPLIT(dev)) { i2c_reg = PCH_GPIOE; @@ -2606,31 +2608,29 @@ bool intel_sdvo_init(struct drm_device *dev, int sdvo_reg) /* Wrap with our custom algo which switches to DDC mode */ intel_encoder->ddc_bus->algo = &intel_sdvo_i2c_bit_algo; - /* encoder type will be decided later */ - drm_encoder_init(dev, &intel_encoder->base, &intel_sdvo_enc_funcs, 0); drm_encoder_helper_add(&intel_encoder->base, &intel_sdvo_helper_funcs); /* In default case sdvo lvds is false */ if (!intel_sdvo_get_capabilities(intel_sdvo, &intel_sdvo->caps)) - goto err_enc; + goto err_i2c; if (intel_sdvo_output_setup(intel_sdvo, intel_sdvo->caps.output_flags) != true) { DRM_DEBUG_KMS("SDVO output failed to setup on SDVO%c\n", IS_SDVOB(sdvo_reg) ? 'B' : 'C'); - goto err_enc; + goto err_i2c; } intel_sdvo_select_ddc_bus(dev_priv, intel_sdvo, sdvo_reg); /* Set the input timing to the screen. Assume always input 0. */ if (!intel_sdvo_set_target_input(intel_sdvo)) - goto err_enc; + goto err_i2c; if (!intel_sdvo_get_input_pixel_clock_range(intel_sdvo, &intel_sdvo->pixel_clock_min, &intel_sdvo->pixel_clock_max)) - goto err_enc; + goto err_i2c; DRM_DEBUG_KMS("%s device VID/DID: %02X:%02X.%02X, " "clock range %dMHz - %dMHz, " @@ -2650,14 +2650,13 @@ bool intel_sdvo_init(struct drm_device *dev, int sdvo_reg) (SDVO_OUTPUT_TMDS1 | SDVO_OUTPUT_RGB1) ? 'Y' : 'N'); return true; -err_enc: - drm_encoder_cleanup(&intel_encoder->base); err_i2c: if (intel_encoder->ddc_bus != NULL) intel_i2c_destroy(intel_encoder->ddc_bus); if (intel_encoder->i2c_bus != NULL) intel_i2c_destroy(intel_encoder->i2c_bus); err_inteloutput: + drm_encoder_cleanup(&intel_encoder->base); kfree(intel_sdvo); return false; -- cgit v1.1 From f899fc64cda8569d0529452aafc0da31c042df2e Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Tue, 20 Jul 2010 15:44:45 -0700 Subject: drm/i915: use GMBUS to manage i2c links Use the GMBUS interface rather than direct bit banging to grab the EDID over DDC (and for other forms of auxiliary communication with external display controllers). The hope is that this method will be much faster and more reliable than bit banging for fetching EDIDs from buggy monitors or through switches, though we still preserve the bit banging as a fallback in case GMBUS fails. Based on an original patch by Jesse Barnes. Cc: Jesse Barnes Signed-off-by: Chris Wilson --- drivers/gpu/drm/drm_edid.c | 1 - drivers/gpu/drm/i915/dvo_ch7017.c | 9 +- drivers/gpu/drm/i915/dvo_ch7xxx.c | 10 +- drivers/gpu/drm/i915/dvo_ivch.c | 10 +- drivers/gpu/drm/i915/dvo_sil164.c | 10 +- drivers/gpu/drm/i915/dvo_tfp410.c | 10 +- drivers/gpu/drm/i915/i915_dma.c | 2 + drivers/gpu/drm/i915/i915_drv.h | 14 +- drivers/gpu/drm/i915/i915_reg.h | 51 ++++- drivers/gpu/drm/i915/i915_suspend.c | 4 +- drivers/gpu/drm/i915/intel_bios.c | 16 +- drivers/gpu/drm/i915/intel_crt.c | 48 +---- drivers/gpu/drm/i915/intel_display.c | 6 - drivers/gpu/drm/i915/intel_dp.c | 3 +- drivers/gpu/drm/i915/intel_drv.h | 19 +- drivers/gpu/drm/i915/intel_dvo.c | 33 ++- drivers/gpu/drm/i915/intel_hdmi.c | 38 ++-- drivers/gpu/drm/i915/intel_i2c.c | 381 ++++++++++++++++++++++++----------- drivers/gpu/drm/i915/intel_lvds.c | 16 +- drivers/gpu/drm/i915/intel_modes.c | 16 +- drivers/gpu/drm/i915/intel_sdvo.c | 163 +++++---------- 21 files changed, 441 insertions(+), 419 deletions(-) diff --git a/drivers/gpu/drm/drm_edid.c b/drivers/gpu/drm/drm_edid.c index 96e9631..fd033eb 100644 --- a/drivers/gpu/drm/drm_edid.c +++ b/drivers/gpu/drm/drm_edid.c @@ -30,7 +30,6 @@ #include #include #include -#include #include "drmP.h" #include "drm_edid.h" #include "drm_edid_modes.h" diff --git a/drivers/gpu/drm/i915/dvo_ch7017.c b/drivers/gpu/drm/i915/dvo_ch7017.c index 14d5980..0bc8ce1 100644 --- a/drivers/gpu/drm/i915/dvo_ch7017.c +++ b/drivers/gpu/drm/i915/dvo_ch7017.c @@ -168,7 +168,6 @@ static void ch7017_dpms(struct intel_dvo_device *dvo, int mode); static bool ch7017_read(struct intel_dvo_device *dvo, int addr, uint8_t *val) { struct i2c_adapter *adapter = dvo->i2c_bus; - struct intel_i2c_chan *i2cbus = container_of(adapter, struct intel_i2c_chan, adapter); u8 out_buf[2]; u8 in_buf[2]; @@ -190,7 +189,7 @@ static bool ch7017_read(struct intel_dvo_device *dvo, int addr, uint8_t *val) out_buf[0] = addr; out_buf[1] = 0; - if (i2c_transfer(&i2cbus->adapter, msgs, 2) == 2) { + if (i2c_transfer(adapter, msgs, 2) == 2) { *val= in_buf[0]; return true; }; @@ -201,7 +200,6 @@ static bool ch7017_read(struct intel_dvo_device *dvo, int addr, uint8_t *val) static bool ch7017_write(struct intel_dvo_device *dvo, int addr, uint8_t val) { struct i2c_adapter *adapter = dvo->i2c_bus; - struct intel_i2c_chan *i2cbus = container_of(adapter, struct intel_i2c_chan, adapter); uint8_t out_buf[2]; struct i2c_msg msg = { .addr = dvo->slave_addr, @@ -213,7 +211,7 @@ static bool ch7017_write(struct intel_dvo_device *dvo, int addr, uint8_t val) out_buf[0] = addr; out_buf[1] = val; - if (i2c_transfer(&i2cbus->adapter, &msg, 1) == 1) + if (i2c_transfer(adapter, &msg, 1) == 1) return true; return false; @@ -223,7 +221,6 @@ static bool ch7017_write(struct intel_dvo_device *dvo, int addr, uint8_t val) static bool ch7017_init(struct intel_dvo_device *dvo, struct i2c_adapter *adapter) { - struct intel_i2c_chan *i2cbus = container_of(adapter, struct intel_i2c_chan, adapter); struct ch7017_priv *priv; uint8_t val; @@ -242,7 +239,7 @@ static bool ch7017_init(struct intel_dvo_device *dvo, val != CH7019_DEVICE_ID_VALUE) { DRM_DEBUG_KMS("ch701x not detected, got %d: from %s " "Slave %d.\n", - val, i2cbus->adapter.name,dvo->slave_addr); + val, adapter->name,dvo->slave_addr); goto fail; } diff --git a/drivers/gpu/drm/i915/dvo_ch7xxx.c b/drivers/gpu/drm/i915/dvo_ch7xxx.c index 6f1944b..7eaa94e 100644 --- a/drivers/gpu/drm/i915/dvo_ch7xxx.c +++ b/drivers/gpu/drm/i915/dvo_ch7xxx.c @@ -113,7 +113,6 @@ static bool ch7xxx_readb(struct intel_dvo_device *dvo, int addr, uint8_t *ch) { struct ch7xxx_priv *ch7xxx= dvo->dev_priv; struct i2c_adapter *adapter = dvo->i2c_bus; - struct intel_i2c_chan *i2cbus = container_of(adapter, struct intel_i2c_chan, adapter); u8 out_buf[2]; u8 in_buf[2]; @@ -135,14 +134,14 @@ static bool ch7xxx_readb(struct intel_dvo_device *dvo, int addr, uint8_t *ch) out_buf[0] = addr; out_buf[1] = 0; - if (i2c_transfer(&i2cbus->adapter, msgs, 2) == 2) { + if (i2c_transfer(adapter, msgs, 2) == 2) { *ch = in_buf[0]; return true; }; if (!ch7xxx->quiet) { DRM_DEBUG_KMS("Unable to read register 0x%02x from %s:%02x.\n", - addr, i2cbus->adapter.name, dvo->slave_addr); + addr, adapter->name, dvo->slave_addr); } return false; } @@ -152,7 +151,6 @@ static bool ch7xxx_writeb(struct intel_dvo_device *dvo, int addr, uint8_t ch) { struct ch7xxx_priv *ch7xxx = dvo->dev_priv; struct i2c_adapter *adapter = dvo->i2c_bus; - struct intel_i2c_chan *i2cbus = container_of(adapter, struct intel_i2c_chan, adapter); uint8_t out_buf[2]; struct i2c_msg msg = { .addr = dvo->slave_addr, @@ -164,12 +162,12 @@ static bool ch7xxx_writeb(struct intel_dvo_device *dvo, int addr, uint8_t ch) out_buf[0] = addr; out_buf[1] = ch; - if (i2c_transfer(&i2cbus->adapter, &msg, 1) == 1) + if (i2c_transfer(adapter, &msg, 1) == 1) return true; if (!ch7xxx->quiet) { DRM_DEBUG_KMS("Unable to write register 0x%02x to %s:%d.\n", - addr, i2cbus->adapter.name, dvo->slave_addr); + addr, adapter->name, dvo->slave_addr); } return false; diff --git a/drivers/gpu/drm/i915/dvo_ivch.c b/drivers/gpu/drm/i915/dvo_ivch.c index a2ec3f4..a12ed94 100644 --- a/drivers/gpu/drm/i915/dvo_ivch.c +++ b/drivers/gpu/drm/i915/dvo_ivch.c @@ -167,7 +167,6 @@ static bool ivch_read(struct intel_dvo_device *dvo, int addr, uint16_t *data) { struct ivch_priv *priv = dvo->dev_priv; struct i2c_adapter *adapter = dvo->i2c_bus; - struct intel_i2c_chan *i2cbus = container_of(adapter, struct intel_i2c_chan, adapter); u8 out_buf[1]; u8 in_buf[2]; @@ -193,7 +192,7 @@ static bool ivch_read(struct intel_dvo_device *dvo, int addr, uint16_t *data) out_buf[0] = addr; - if (i2c_transfer(&i2cbus->adapter, msgs, 3) == 3) { + if (i2c_transfer(adapter, msgs, 3) == 3) { *data = (in_buf[1] << 8) | in_buf[0]; return true; }; @@ -201,7 +200,7 @@ static bool ivch_read(struct intel_dvo_device *dvo, int addr, uint16_t *data) if (!priv->quiet) { DRM_DEBUG_KMS("Unable to read register 0x%02x from " "%s:%02x.\n", - addr, i2cbus->adapter.name, dvo->slave_addr); + addr, adapter->name, dvo->slave_addr); } return false; } @@ -211,7 +210,6 @@ static bool ivch_write(struct intel_dvo_device *dvo, int addr, uint16_t data) { struct ivch_priv *priv = dvo->dev_priv; struct i2c_adapter *adapter = dvo->i2c_bus; - struct intel_i2c_chan *i2cbus = container_of(adapter, struct intel_i2c_chan, adapter); u8 out_buf[3]; struct i2c_msg msg = { .addr = dvo->slave_addr, @@ -224,12 +222,12 @@ static bool ivch_write(struct intel_dvo_device *dvo, int addr, uint16_t data) out_buf[1] = data & 0xff; out_buf[2] = data >> 8; - if (i2c_transfer(&i2cbus->adapter, &msg, 1) == 1) + if (i2c_transfer(adapter, &msg, 1) == 1) return true; if (!priv->quiet) { DRM_DEBUG_KMS("Unable to write register 0x%02x to %s:%d.\n", - addr, i2cbus->adapter.name, dvo->slave_addr); + addr, adapter->name, dvo->slave_addr); } return false; diff --git a/drivers/gpu/drm/i915/dvo_sil164.c b/drivers/gpu/drm/i915/dvo_sil164.c index 9b8e676..e4b4091 100644 --- a/drivers/gpu/drm/i915/dvo_sil164.c +++ b/drivers/gpu/drm/i915/dvo_sil164.c @@ -69,7 +69,6 @@ static bool sil164_readb(struct intel_dvo_device *dvo, int addr, uint8_t *ch) { struct sil164_priv *sil = dvo->dev_priv; struct i2c_adapter *adapter = dvo->i2c_bus; - struct intel_i2c_chan *i2cbus = container_of(adapter, struct intel_i2c_chan, adapter); u8 out_buf[2]; u8 in_buf[2]; @@ -91,14 +90,14 @@ static bool sil164_readb(struct intel_dvo_device *dvo, int addr, uint8_t *ch) out_buf[0] = addr; out_buf[1] = 0; - if (i2c_transfer(&i2cbus->adapter, msgs, 2) == 2) { + if (i2c_transfer(adapter, msgs, 2) == 2) { *ch = in_buf[0]; return true; }; if (!sil->quiet) { DRM_DEBUG_KMS("Unable to read register 0x%02x from %s:%02x.\n", - addr, i2cbus->adapter.name, dvo->slave_addr); + addr, adapter->name, dvo->slave_addr); } return false; } @@ -107,7 +106,6 @@ static bool sil164_writeb(struct intel_dvo_device *dvo, int addr, uint8_t ch) { struct sil164_priv *sil= dvo->dev_priv; struct i2c_adapter *adapter = dvo->i2c_bus; - struct intel_i2c_chan *i2cbus = container_of(adapter, struct intel_i2c_chan, adapter); uint8_t out_buf[2]; struct i2c_msg msg = { .addr = dvo->slave_addr, @@ -119,12 +117,12 @@ static bool sil164_writeb(struct intel_dvo_device *dvo, int addr, uint8_t ch) out_buf[0] = addr; out_buf[1] = ch; - if (i2c_transfer(&i2cbus->adapter, &msg, 1) == 1) + if (i2c_transfer(adapter, &msg, 1) == 1) return true; if (!sil->quiet) { DRM_DEBUG_KMS("Unable to write register 0x%02x to %s:%d.\n", - addr, i2cbus->adapter.name, dvo->slave_addr); + addr, adapter->name, dvo->slave_addr); } return false; diff --git a/drivers/gpu/drm/i915/dvo_tfp410.c b/drivers/gpu/drm/i915/dvo_tfp410.c index 56f6642..8ab2855 100644 --- a/drivers/gpu/drm/i915/dvo_tfp410.c +++ b/drivers/gpu/drm/i915/dvo_tfp410.c @@ -94,7 +94,6 @@ static bool tfp410_readb(struct intel_dvo_device *dvo, int addr, uint8_t *ch) { struct tfp410_priv *tfp = dvo->dev_priv; struct i2c_adapter *adapter = dvo->i2c_bus; - struct intel_i2c_chan *i2cbus = container_of(adapter, struct intel_i2c_chan, adapter); u8 out_buf[2]; u8 in_buf[2]; @@ -116,14 +115,14 @@ static bool tfp410_readb(struct intel_dvo_device *dvo, int addr, uint8_t *ch) out_buf[0] = addr; out_buf[1] = 0; - if (i2c_transfer(&i2cbus->adapter, msgs, 2) == 2) { + if (i2c_transfer(adapter, msgs, 2) == 2) { *ch = in_buf[0]; return true; }; if (!tfp->quiet) { DRM_DEBUG_KMS("Unable to read register 0x%02x from %s:%02x.\n", - addr, i2cbus->adapter.name, dvo->slave_addr); + addr, adapter->name, dvo->slave_addr); } return false; } @@ -132,7 +131,6 @@ static bool tfp410_writeb(struct intel_dvo_device *dvo, int addr, uint8_t ch) { struct tfp410_priv *tfp = dvo->dev_priv; struct i2c_adapter *adapter = dvo->i2c_bus; - struct intel_i2c_chan *i2cbus = container_of(adapter, struct intel_i2c_chan, adapter); uint8_t out_buf[2]; struct i2c_msg msg = { .addr = dvo->slave_addr, @@ -144,12 +142,12 @@ static bool tfp410_writeb(struct intel_dvo_device *dvo, int addr, uint8_t ch) out_buf[0] = addr; out_buf[1] = ch; - if (i2c_transfer(&i2cbus->adapter, &msg, 1) == 1) + if (i2c_transfer(adapter, &msg, 1) == 1) return true; if (!tfp->quiet) { DRM_DEBUG_KMS("Unable to write register 0x%02x to %s:%d.\n", - addr, i2cbus->adapter.name, dvo->slave_addr); + addr, adapter->name, dvo->slave_addr); } return false; diff --git a/drivers/gpu/drm/i915/i915_dma.c b/drivers/gpu/drm/i915/i915_dma.c index 7c7d1bc..39aaffe 100644 --- a/drivers/gpu/drm/i915/i915_dma.c +++ b/drivers/gpu/drm/i915/i915_dma.c @@ -2001,6 +2001,7 @@ int i915_driver_load(struct drm_device *dev, unsigned long flags) /* Try to make sure MCHBAR is enabled before poking at it */ intel_setup_mchbar(dev); + intel_setup_gmbus(dev); intel_opregion_setup(dev); i915_gem_load(dev); @@ -2155,6 +2156,7 @@ int i915_driver_unload(struct drm_device *dev) intel_cleanup_overlay(dev); } + intel_teardown_gmbus(dev); intel_teardown_mchbar(dev); destroy_workqueue(dev_priv->wq); diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index b0692c4..cf08128 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -34,6 +34,7 @@ #include "intel_bios.h" #include "intel_ringbuffer.h" #include +#include #include /* General customization: @@ -246,6 +247,12 @@ typedef struct drm_i915_private { void __iomem *regs; + struct intel_gmbus { + struct i2c_adapter adapter; + struct i2c_adapter *force_bitbanging; + int pin; + } *gmbus; + struct pci_dev *bridge_dev; struct intel_ring_buffer render_ring; struct intel_ring_buffer bsd_ring; @@ -339,7 +346,7 @@ typedef struct drm_i915_private { struct notifier_block lid_notifier; - int crt_ddc_bus; /* 0 = unknown, else GPIO to use for CRT DDC */ + int crt_ddc_pin; struct drm_i915_fence_reg fence_regs[16]; /* assume 965 */ int fence_reg_start; /* 4 if userland hasn't ioctl'd us yet */ int num_fence_regs; /* 8 on pre-965, 16 otherwise */ @@ -1070,6 +1077,11 @@ extern int i915_restore_state(struct drm_device *dev); extern int i915_save_state(struct drm_device *dev); extern int i915_restore_state(struct drm_device *dev); +/* intel_i2c.c */ +extern int intel_setup_gmbus(struct drm_device *dev); +extern void intel_teardown_gmbus(struct drm_device *dev); +extern void intel_i2c_reset(struct drm_device *dev); + /* intel_opregion.c */ extern int intel_opregion_setup(struct drm_device *dev); #ifdef CONFIG_ACPI diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index fd229ab..18e3749 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -583,12 +583,51 @@ # define GPIO_DATA_VAL_IN (1 << 12) # define GPIO_DATA_PULLUP_DISABLE (1 << 13) -#define GMBUS0 0x5100 -#define GMBUS1 0x5104 -#define GMBUS2 0x5108 -#define GMBUS3 0x510c -#define GMBUS4 0x5110 -#define GMBUS5 0x5120 +#define GMBUS0 0x5100 /* clock/port select */ +#define GMBUS_RATE_100KHZ (0<<8) +#define GMBUS_RATE_50KHZ (1<<8) +#define GMBUS_RATE_400KHZ (2<<8) /* reserved on Pineview */ +#define GMBUS_RATE_1MHZ (3<<8) /* reserved on Pineview */ +#define GMBUS_HOLD_EXT (1<<7) /* 300ns hold time, rsvd on Pineview */ +#define GMBUS_PORT_DISABLED 0 +#define GMBUS_PORT_SSC 1 +#define GMBUS_PORT_VGADDC 2 +#define GMBUS_PORT_PANEL 3 +#define GMBUS_PORT_DPC 4 /* HDMIC */ +#define GMBUS_PORT_DPB 5 /* SDVO, HDMIB */ + /* 6 reserved */ +#define GMBUS_PORT_DPD 7 /* HDMID */ +#define GMBUS_NUM_PORTS 8 +#define GMBUS1 0x5104 /* command/status */ +#define GMBUS_SW_CLR_INT (1<<31) +#define GMBUS_SW_RDY (1<<30) +#define GMBUS_ENT (1<<29) /* enable timeout */ +#define GMBUS_CYCLE_NONE (0<<25) +#define GMBUS_CYCLE_WAIT (1<<25) +#define GMBUS_CYCLE_INDEX (2<<25) +#define GMBUS_CYCLE_STOP (4<<25) +#define GMBUS_BYTE_COUNT_SHIFT 16 +#define GMBUS_SLAVE_INDEX_SHIFT 8 +#define GMBUS_SLAVE_ADDR_SHIFT 1 +#define GMBUS_SLAVE_READ (1<<0) +#define GMBUS_SLAVE_WRITE (0<<0) +#define GMBUS2 0x5108 /* status */ +#define GMBUS_INUSE (1<<15) +#define GMBUS_HW_WAIT_PHASE (1<<14) +#define GMBUS_STALL_TIMEOUT (1<<13) +#define GMBUS_INT (1<<12) +#define GMBUS_HW_RDY (1<<11) +#define GMBUS_SATOER (1<<10) +#define GMBUS_ACTIVE (1<<9) +#define GMBUS3 0x510c /* data buffer bytes 3-0 */ +#define GMBUS4 0x5110 /* interrupt mask (Pineview+) */ +#define GMBUS_SLAVE_TIMEOUT_EN (1<<4) +#define GMBUS_NAK_EN (1<<3) +#define GMBUS_IDLE_EN (1<<2) +#define GMBUS_HW_WAIT_EN (1<<1) +#define GMBUS_HW_RDY_EN (1<<0) +#define GMBUS5 0x5120 /* byte index */ +#define GMBUS_2BYTE_INDEX_EN (1<<31) /* * Clock control & power management diff --git a/drivers/gpu/drm/i915/i915_suspend.c b/drivers/gpu/drm/i915/i915_suspend.c index 2c6b98f..5c0de65 100644 --- a/drivers/gpu/drm/i915/i915_suspend.c +++ b/drivers/gpu/drm/i915/i915_suspend.c @@ -860,9 +860,7 @@ int i915_restore_state(struct drm_device *dev) for (i = 0; i < 3; i++) I915_WRITE(SWF30 + (i << 2), dev_priv->saveSWF2[i]); - /* I2C state */ - intel_i2c_reset_gmbus(dev); + intel_i2c_reset(dev); return 0; } - diff --git a/drivers/gpu/drm/i915/intel_bios.c b/drivers/gpu/drm/i915/intel_bios.c index 8986a4b..d11bbca 100644 --- a/drivers/gpu/drm/i915/intel_bios.c +++ b/drivers/gpu/drm/i915/intel_bios.c @@ -291,14 +291,6 @@ parse_general_definitions(struct drm_i915_private *dev_priv, struct bdb_header *bdb) { struct bdb_general_definitions *general; - const int crt_bus_map_table[] = { - GPIOB, - GPIOA, - GPIOC, - GPIOD, - GPIOE, - GPIOF, - }; general = find_section(bdb, BDB_GENERAL_DEFINITIONS); if (general) { @@ -306,10 +298,8 @@ parse_general_definitions(struct drm_i915_private *dev_priv, if (block_size >= sizeof(*general)) { int bus_pin = general->crt_ddc_gmbus_pin; DRM_DEBUG_KMS("crt_ddc_bus_pin: %d\n", bus_pin); - if ((bus_pin >= 1) && (bus_pin <= 6)) { - dev_priv->crt_ddc_bus = - crt_bus_map_table[bus_pin-1]; - } + if (bus_pin >= 1 && bus_pin <= 6) + dev_priv->crt_ddc_pin = bus_pin - 1; } else { DRM_DEBUG_KMS("BDB_GD too small (%d). Invalid.\n", block_size); @@ -533,6 +523,8 @@ intel_init_bios(struct drm_device *dev) struct bdb_header *bdb = NULL; u8 __iomem *bios = NULL; + dev_priv->crt_ddc_pin = GMBUS_PORT_VGADDC; + /* XXX Should this validation be moved to intel_opregion.c? */ if (dev_priv->opregion.vbt) { struct vbt_header *vbt = dev_priv->opregion.vbt; diff --git a/drivers/gpu/drm/i915/intel_crt.c b/drivers/gpu/drm/i915/intel_crt.c index 2353da6..8b782ee 100644 --- a/drivers/gpu/drm/i915/intel_crt.c +++ b/drivers/gpu/drm/i915/intel_crt.c @@ -264,12 +264,13 @@ static bool intel_crt_detect_hotplug(struct drm_connector *connector) static bool intel_crt_detect_ddc(struct drm_encoder *encoder) { struct intel_encoder *intel_encoder = to_intel_encoder(encoder); + struct drm_i915_private *dev_priv = encoder->dev->dev_private; /* CRT should always be at 0, but check anyway */ if (intel_encoder->type != INTEL_OUTPUT_ANALOG) return false; - return intel_ddc_probe(intel_encoder); + return intel_ddc_probe(intel_encoder, dev_priv->crt_ddc_pin); } static enum drm_connector_status @@ -445,29 +446,18 @@ static void intel_crt_destroy(struct drm_connector *connector) static int intel_crt_get_modes(struct drm_connector *connector) { - struct intel_encoder *encoder = intel_attached_encoder(connector); - struct i2c_adapter *ddc_bus; struct drm_device *dev = connector->dev; + struct drm_i915_private *dev_priv = dev->dev_private; int ret; - ret = intel_ddc_get_modes(connector, encoder->ddc_bus); + ret = intel_ddc_get_modes(connector, + &dev_priv->gmbus[dev_priv->crt_ddc_pin].adapter); if (ret || !IS_G4X(dev)) - goto end; + return ret; /* Try to probe digital port for output in DVI-I -> VGA mode. */ - ddc_bus = intel_i2c_create(encoder, GPIOD, "CRTDDC_D"); - if (!ddc_bus) { - dev_printk(KERN_ERR, &connector->dev->pdev->dev, - "DDC bus registration failed for CRTDDC_D.\n"); - goto end; - } - /* Try to get modes by GPIOD port */ - ret = intel_ddc_get_modes(connector, ddc_bus); - intel_i2c_destroy(ddc_bus); - -end: - return ret; - + return intel_ddc_get_modes(connector, + &dev_priv->gmbus[GMBUS_PORT_DPB].adapter); } static int intel_crt_set_property(struct drm_connector *connector, @@ -513,7 +503,6 @@ void intel_crt_init(struct drm_device *dev) struct intel_encoder *intel_encoder; struct intel_connector *intel_connector; struct drm_i915_private *dev_priv = dev->dev_private; - u32 i2c_reg; intel_encoder = kzalloc(sizeof(struct intel_encoder), GFP_KERNEL); if (!intel_encoder) @@ -534,27 +523,6 @@ void intel_crt_init(struct drm_device *dev) intel_connector_attach_encoder(intel_connector, intel_encoder); - /* Set up the DDC bus. */ - if (HAS_PCH_SPLIT(dev)) - i2c_reg = PCH_GPIOA; - else { - i2c_reg = GPIOA; - /* Use VBT information for CRT DDC if available */ - if (dev_priv->crt_ddc_bus != 0) - i2c_reg = dev_priv->crt_ddc_bus; - } - intel_encoder->ddc_bus = intel_i2c_create(intel_encoder, - i2c_reg, "CRTDDC_A"); - if (!intel_encoder->ddc_bus) { - dev_printk(KERN_ERR, &dev->pdev->dev, "DDC bus registration " - "failed.\n"); - drm_connector_cleanup(&intel_connector->base); - kfree(intel_connector); - drm_encoder_cleanup(&intel_encoder->base); - kfree(intel_encoder); - return; - } - intel_encoder->type = INTEL_OUTPUT_ANALOG; intel_encoder->clone_mask = (1 << INTEL_SDVO_NON_TV_CLONE_BIT) | (1 << INTEL_ANALOG_CLONE_BIT) | diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 11d643a..86ea389 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -2530,12 +2530,6 @@ void intel_encoder_destroy(struct drm_encoder *encoder) { struct intel_encoder *intel_encoder = to_intel_encoder(encoder); - if (intel_encoder->ddc_bus) - intel_i2c_destroy(intel_encoder->ddc_bus); - - if (intel_encoder->i2c_bus) - intel_i2c_destroy(intel_encoder->i2c_bus); - drm_encoder_cleanup(encoder); kfree(intel_encoder); } diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c index 208a4ec..9a87ec5 100644 --- a/drivers/gpu/drm/i915/intel_dp.c +++ b/drivers/gpu/drm/i915/intel_dp.c @@ -1490,7 +1490,7 @@ static int intel_dp_get_modes(struct drm_connector *connector) /* We should parse the EDID data and find out if it has an audio sink */ - ret = intel_ddc_get_modes(connector, intel_dp->base.ddc_bus); + ret = intel_ddc_get_modes(connector, &intel_dp->adapter); if (ret) { if ((IS_eDP(intel_dp) || IS_PCH_eDP(intel_dp)) && !dev_priv->panel_fixed_mode) { @@ -1705,7 +1705,6 @@ intel_dp_init(struct drm_device *dev, int output_reg) intel_dp_i2c_init(intel_dp, intel_connector, name); - intel_encoder->ddc_bus = &intel_dp->adapter; intel_encoder->hot_plug = intel_dp_hot_plug; if (output_reg == DP_A || IS_PCH_eDP(intel_dp)) { diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index 8fe6b73..60ce930 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -26,8 +26,6 @@ #define __INTEL_DRV_H__ #include -#include -#include #include "i915_drv.h" #include "drm_crtc.h" #include "drm_crtc_helper.h" @@ -127,13 +125,6 @@ intel_mode_get_pixel_multiplier(const struct drm_display_mode *mode) return (mode->private_flags & INTEL_MODE_PIXEL_MULTIPLIER_MASK) >> INTEL_MODE_PIXEL_MULTIPLIER_SHIFT; } -struct intel_i2c_chan { - struct intel_encoder *encoder; - u32 reg; /* GPIO reg */ - struct i2c_adapter adapter; - struct i2c_algo_bit_data algo; -}; - struct intel_framebuffer { struct drm_framebuffer base; struct drm_gem_object *obj; @@ -149,8 +140,6 @@ struct intel_fbdev { struct intel_encoder { struct drm_encoder base; int type; - struct i2c_adapter *i2c_bus; - struct i2c_adapter *ddc_bus; bool load_detect_temp; bool needs_tv_clock; void (*hot_plug)(struct intel_encoder *); @@ -206,14 +195,8 @@ struct intel_unpin_work { bool enable_stall_check; }; -struct i2c_adapter *intel_i2c_create(struct intel_encoder *encoder, - const u32 reg, - const char *name); -void intel_i2c_destroy(struct i2c_adapter *adapter); int intel_ddc_get_modes(struct drm_connector *c, struct i2c_adapter *adapter); -extern bool intel_ddc_probe(struct intel_encoder *intel_encoder); -void intel_i2c_quirk_set(struct drm_device *dev, bool enable); -void intel_i2c_reset_gmbus(struct drm_device *dev); +extern bool intel_ddc_probe(struct intel_encoder *intel_encoder, int ddc_bus); extern void intel_crt_init(struct drm_device *dev); extern void intel_hdmi_init(struct drm_device *dev, int sdvox_reg); diff --git a/drivers/gpu/drm/i915/intel_dvo.c b/drivers/gpu/drm/i915/intel_dvo.c index d8a586b..1ee0dbb 100644 --- a/drivers/gpu/drm/i915/intel_dvo.c +++ b/drivers/gpu/drm/i915/intel_dvo.c @@ -72,7 +72,7 @@ static const struct intel_dvo_device intel_dvo_devices[] = { .name = "ch7017", .dvo_reg = DVOC, .slave_addr = 0x75, - .gpio = GPIOE, + .gpio = GMBUS_PORT_DPD, .dev_ops = &ch7017_ops, } }; @@ -81,6 +81,7 @@ struct intel_dvo { struct intel_encoder base; struct intel_dvo_device dev; + int ddc_bus; struct drm_display_mode *panel_fixed_mode; bool panel_wants_dither; @@ -235,13 +236,15 @@ static enum drm_connector_status intel_dvo_detect(struct drm_connector *connecto static int intel_dvo_get_modes(struct drm_connector *connector) { struct intel_dvo *intel_dvo = intel_attached_dvo(connector); + struct drm_i915_private *dev_priv = connector->dev->dev_private; /* We should probably have an i2c driver get_modes function for those * devices which will have a fixed set of modes determined by the chip * (TV-out, for example), but for now with just TMDS and LVDS, * that's not the case. */ - intel_ddc_get_modes(connector, intel_dvo->base.ddc_bus); + intel_ddc_get_modes(connector, + &dev_priv->gmbus[intel_dvo->ddc_bus].adapter); if (!list_empty(&connector->probed_modes)) return 1; @@ -341,10 +344,10 @@ intel_dvo_get_current_mode(struct drm_connector *connector) void intel_dvo_init(struct drm_device *dev) { + struct drm_i915_private *dev_priv = dev->dev_private; struct intel_encoder *intel_encoder; struct intel_dvo *intel_dvo; struct intel_connector *intel_connector; - struct i2c_adapter *i2cbus = NULL; int ret = 0; int i; int encoder_type = DRM_MODE_ENCODER_NONE; @@ -364,15 +367,13 @@ void intel_dvo_init(struct drm_device *dev) &intel_dvo_enc_funcs, encoder_type); /* Set up the DDC bus */ - intel_encoder->ddc_bus = intel_i2c_create(intel_encoder, - GPIOD, "DVODDC_D"); - if (!intel_encoder->ddc_bus) - goto free_intel; + intel_dvo->ddc_bus = GMBUS_PORT_DPB; /* Now, try to find a controller */ for (i = 0; i < ARRAY_SIZE(intel_dvo_devices); i++) { struct drm_connector *connector = &intel_connector->base; const struct intel_dvo_device *dvo = &intel_dvo_devices[i]; + struct i2c_adapter *i2c; int gpio; /* Allow the I2C driver info to specify the GPIO to be used in @@ -382,23 +383,18 @@ void intel_dvo_init(struct drm_device *dev) if (dvo->gpio != 0) gpio = dvo->gpio; else if (dvo->type == INTEL_DVO_CHIP_LVDS) - gpio = GPIOB; + gpio = GMBUS_PORT_PANEL; else - gpio = GPIOE; + gpio = GMBUS_PORT_DPD; /* Set up the I2C bus necessary for the chip we're probing. * It appears that everything is on GPIOE except for panels * on i830 laptops, which are on GPIOB (DVOA). */ - if (i2cbus != NULL) - intel_i2c_destroy(i2cbus); - i2cbus = intel_i2c_create(intel_encoder, gpio, - gpio == GPIOB ? "DVOI2C_B" : "DVOI2C_E"); - if (i2cbus == NULL) - continue; + i2c = &dev_priv->gmbus[gpio].adapter; intel_dvo->dev = *dvo; - ret = dvo->dev_ops->init(&intel_dvo->dev, i2cbus); + ret = dvo->dev_ops->init(&intel_dvo->dev, i2c); if (!ret) continue; @@ -451,11 +447,6 @@ void intel_dvo_init(struct drm_device *dev) return; } - intel_i2c_destroy(intel_encoder->ddc_bus); - /* Didn't find a chip, so tear down. */ - if (i2cbus != NULL) - intel_i2c_destroy(i2cbus); -free_intel: drm_encoder_cleanup(&intel_encoder->base); kfree(intel_dvo); kfree(intel_connector); diff --git a/drivers/gpu/drm/i915/intel_hdmi.c b/drivers/gpu/drm/i915/intel_hdmi.c index 783924c..f814cb0 100644 --- a/drivers/gpu/drm/i915/intel_hdmi.c +++ b/drivers/gpu/drm/i915/intel_hdmi.c @@ -40,6 +40,7 @@ struct intel_hdmi { struct intel_encoder base; u32 sdvox_reg; + int ddc_bus; bool has_hdmi_sink; }; @@ -148,11 +149,13 @@ static enum drm_connector_status intel_hdmi_detect(struct drm_connector *connector) { struct intel_hdmi *intel_hdmi = intel_attached_hdmi(connector); - struct edid *edid = NULL; + struct drm_i915_private *dev_priv = connector->dev->dev_private; + struct edid *edid; enum drm_connector_status status = connector_status_disconnected; intel_hdmi->has_hdmi_sink = false; - edid = drm_get_edid(connector, intel_hdmi->base.ddc_bus); + edid = drm_get_edid(connector, + &dev_priv->gmbus[intel_hdmi->ddc_bus].adapter); if (edid) { if (edid->input & DRM_EDID_INPUT_DIGITAL) { @@ -169,12 +172,14 @@ intel_hdmi_detect(struct drm_connector *connector) static int intel_hdmi_get_modes(struct drm_connector *connector) { struct intel_hdmi *intel_hdmi = intel_attached_hdmi(connector); + struct drm_i915_private *dev_priv = connector->dev->dev_private; /* We should parse the EDID data and find out if it's an HDMI sink so * we can send audio to it. */ - return intel_ddc_get_modes(connector, intel_hdmi->base.ddc_bus); + return intel_ddc_get_modes(connector, + &dev_priv->gmbus[intel_hdmi->ddc_bus].adapter); } static void intel_hdmi_destroy(struct drm_connector *connector) @@ -246,32 +251,25 @@ void intel_hdmi_init(struct drm_device *dev, int sdvox_reg) /* Set up the DDC bus. */ if (sdvox_reg == SDVOB) { intel_encoder->clone_mask = (1 << INTEL_HDMIB_CLONE_BIT); - intel_encoder->ddc_bus = intel_i2c_create(intel_encoder, - GPIOE, "HDMIB"); + intel_hdmi->ddc_bus = GMBUS_PORT_DPB; dev_priv->hotplug_supported_mask |= HDMIB_HOTPLUG_INT_STATUS; } else if (sdvox_reg == SDVOC) { intel_encoder->clone_mask = (1 << INTEL_HDMIC_CLONE_BIT); - intel_encoder->ddc_bus = intel_i2c_create(intel_encoder, - GPIOD, "HDMIC"); + intel_hdmi->ddc_bus = GMBUS_PORT_DPC; dev_priv->hotplug_supported_mask |= HDMIC_HOTPLUG_INT_STATUS; } else if (sdvox_reg == HDMIB) { intel_encoder->clone_mask = (1 << INTEL_HDMID_CLONE_BIT); - intel_encoder->ddc_bus = intel_i2c_create(intel_encoder, - PCH_GPIOE, "HDMIB"); + intel_hdmi->ddc_bus = GMBUS_PORT_DPB; dev_priv->hotplug_supported_mask |= HDMIB_HOTPLUG_INT_STATUS; } else if (sdvox_reg == HDMIC) { intel_encoder->clone_mask = (1 << INTEL_HDMIE_CLONE_BIT); - intel_encoder->ddc_bus = intel_i2c_create(intel_encoder, - PCH_GPIOD, "HDMIC"); + intel_hdmi->ddc_bus = GMBUS_PORT_DPC; dev_priv->hotplug_supported_mask |= HDMIC_HOTPLUG_INT_STATUS; } else if (sdvox_reg == HDMID) { intel_encoder->clone_mask = (1 << INTEL_HDMIF_CLONE_BIT); - intel_encoder->ddc_bus = intel_i2c_create(intel_encoder, - PCH_GPIOF, "HDMID"); + intel_hdmi->ddc_bus = GMBUS_PORT_DPD; dev_priv->hotplug_supported_mask |= HDMID_HOTPLUG_INT_STATUS; } - if (!intel_encoder->ddc_bus) - goto err_connector; intel_hdmi->sdvox_reg = sdvox_reg; @@ -288,14 +286,4 @@ void intel_hdmi_init(struct drm_device *dev, int sdvox_reg) u32 temp = I915_READ(PEG_BAND_GAP_DATA); I915_WRITE(PEG_BAND_GAP_DATA, (temp & ~0xf) | 0xd); } - - return; - -err_connector: - drm_encoder_cleanup(&intel_encoder->base); - drm_connector_cleanup(connector); - kfree(intel_hdmi); - kfree(intel_connector); - - return; } diff --git a/drivers/gpu/drm/i915/intel_i2c.c b/drivers/gpu/drm/i915/intel_i2c.c index d3d65a9..6f4d1289 100644 --- a/drivers/gpu/drm/i915/intel_i2c.c +++ b/drivers/gpu/drm/i915/intel_i2c.c @@ -1,6 +1,6 @@ /* * Copyright (c) 2006 Dave Airlie - * Copyright © 2006-2008 Intel Corporation + * Copyright © 2006-2008,2010 Intel Corporation * Jesse Barnes * * Permission is hereby granted, free of charge, to any person obtaining a @@ -24,10 +24,9 @@ * * Authors: * Eric Anholt + * Chris Wilson */ #include -#include -#include #include #include "drmP.h" #include "drm.h" @@ -35,13 +34,33 @@ #include "i915_drm.h" #include "i915_drv.h" -void intel_i2c_quirk_set(struct drm_device *dev, bool enable) +/* Intel GPIO access functions */ + +#define I2C_RISEFALL_TIME 20 + +struct intel_gpio { + struct i2c_adapter adapter; + struct i2c_algo_bit_data algo; + struct drm_i915_private *dev_priv; + u32 reg; +}; + +void +intel_i2c_reset(struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; + if (HAS_PCH_SPLIT(dev)) + I915_WRITE(PCH_GMBUS0, 0); + else + I915_WRITE(GMBUS0, 0); +} + +static void intel_i2c_quirk_set(struct drm_i915_private *dev_priv, bool enable) +{ u32 val; /* When using bit bashing for I2C, this bit needs to be set to 1 */ - if (!IS_PINEVIEW(dev)) + if (!IS_PINEVIEW(dev_priv->dev)) return; val = I915_READ(DSPCLK_GATE_D); @@ -52,42 +71,30 @@ void intel_i2c_quirk_set(struct drm_device *dev, bool enable) I915_WRITE(DSPCLK_GATE_D, val); } -/* - * Intel GPIO access functions - */ - -#define I2C_RISEFALL_TIME 20 - -static inline struct drm_i915_private * -get_dev_priv(struct intel_i2c_chan *chan) -{ - return chan->encoder->base.dev->dev_private; -} - static int get_clock(void *data) { - struct intel_i2c_chan *chan = data; - struct drm_i915_private *dev_priv = get_dev_priv(chan); - return (I915_READ(chan->reg) & GPIO_CLOCK_VAL_IN) != 0; + struct intel_gpio *gpio = data; + struct drm_i915_private *dev_priv = gpio->dev_priv; + return (I915_READ(gpio->reg) & GPIO_CLOCK_VAL_IN) != 0; } static int get_data(void *data) { - struct intel_i2c_chan *chan = data; - struct drm_i915_private *dev_priv = get_dev_priv(chan); - return (I915_READ(chan->reg) & GPIO_DATA_VAL_IN) != 0; + struct intel_gpio *gpio = data; + struct drm_i915_private *dev_priv = gpio->dev_priv; + return (I915_READ(gpio->reg) & GPIO_DATA_VAL_IN) != 0; } static void set_clock(void *data, int state_high) { - struct intel_i2c_chan *chan = data; - struct drm_i915_private *dev_priv = get_dev_priv(chan); + struct intel_gpio *gpio = data; + struct drm_i915_private *dev_priv = gpio->dev_priv; struct drm_device *dev = dev_priv->dev; u32 reserved = 0, clock_bits; /* On most chips, these bits must be preserved in software. */ if (!IS_I830(dev) && !IS_845G(dev)) - reserved = I915_READ(chan->reg) & (GPIO_DATA_PULLUP_DISABLE | + reserved = I915_READ(gpio->reg) & (GPIO_DATA_PULLUP_DISABLE | GPIO_CLOCK_PULLUP_DISABLE); if (state_high) @@ -95,20 +102,21 @@ static void set_clock(void *data, int state_high) else clock_bits = GPIO_CLOCK_DIR_OUT | GPIO_CLOCK_DIR_MASK | GPIO_CLOCK_VAL_MASK; - I915_WRITE(chan->reg, reserved | clock_bits); - POSTING_READ(chan->reg); + + I915_WRITE(gpio->reg, reserved | clock_bits); + POSTING_READ(gpio->reg); } static void set_data(void *data, int state_high) { - struct intel_i2c_chan *chan = data; - struct drm_i915_private *dev_priv = get_dev_priv(chan); + struct intel_gpio *gpio = data; + struct drm_i915_private *dev_priv = gpio->dev_priv; struct drm_device *dev = dev_priv->dev; u32 reserved = 0, data_bits; /* On most chips, these bits must be preserved in software. */ if (!IS_I830(dev) && !IS_845G(dev)) - reserved = I915_READ(chan->reg) & (GPIO_DATA_PULLUP_DISABLE | + reserved = I915_READ(gpio->reg) & (GPIO_DATA_PULLUP_DISABLE | GPIO_CLOCK_PULLUP_DISABLE); if (state_high) @@ -117,111 +125,258 @@ static void set_data(void *data, int state_high) data_bits = GPIO_DATA_DIR_OUT | GPIO_DATA_DIR_MASK | GPIO_DATA_VAL_MASK; - I915_WRITE(chan->reg, reserved | data_bits); - POSTING_READ(chan->reg); + I915_WRITE(gpio->reg, reserved | data_bits); + POSTING_READ(gpio->reg); } -/* Clears the GMBUS setup. Our driver doesn't make use of the GMBUS I2C - * engine, but if the BIOS leaves it enabled, then that can break our use - * of the bit-banging I2C interfaces. This is notably the case with the - * Mac Mini in EFI mode. - */ -void -intel_i2c_reset_gmbus(struct drm_device *dev) +static struct i2c_adapter * +intel_gpio_create(struct drm_i915_private *dev_priv, u32 pin) { - struct drm_i915_private *dev_priv = dev->dev_private; + static const int map_pin_to_reg[] = { + 0, + GPIOB, + GPIOA, + GPIOC, + GPIOD, + GPIOE, + GPIOF, + }; + struct intel_gpio *gpio; - if (HAS_PCH_SPLIT(dev)) - I915_WRITE(PCH_GMBUS0, 0); - else - I915_WRITE(GMBUS0, 0); -} + if (pin < 1 || pin > 7) + return NULL; -/** - * intel_i2c_create - instantiate an Intel i2c bus using the specified GPIO reg - * @dev: DRM device - * @output: driver specific output device - * @reg: GPIO reg to use - * @name: name for this bus - * @slave_addr: slave address (if fixed) - * - * Creates and registers a new i2c bus with the Linux i2c layer, for use - * in output probing and control (e.g. DDC or SDVO control functions). - * - * Possible values for @reg include: - * %GPIOA - * %GPIOB - * %GPIOC - * %GPIOD - * %GPIOE - * %GPIOF - * %GPIOG - * %GPIOH - * see PRM for details on how these different busses are used. - */ -struct i2c_adapter *intel_i2c_create(struct intel_encoder *encoder, - const u32 reg, - const char *name) -{ - struct intel_i2c_chan *chan; - struct drm_device *dev = encoder->base.dev; + gpio = kzalloc(sizeof(struct intel_gpio), GFP_KERNEL); + if (gpio == NULL) + return NULL; - chan = kzalloc(sizeof(struct intel_i2c_chan), GFP_KERNEL); - if (!chan) - goto out_free; + gpio->reg = map_pin_to_reg[pin]; + if (HAS_PCH_SPLIT(dev_priv->dev)) + gpio->reg += PCH_GPIOA - GPIOA; + gpio->dev_priv = dev_priv; - chan->encoder = encoder; - chan->reg = reg; - snprintf(chan->adapter.name, I2C_NAME_SIZE, "intel drm %s", name); - chan->adapter.owner = THIS_MODULE; - chan->adapter.algo_data = &chan->algo; - chan->adapter.dev.parent = &dev->pdev->dev; - chan->algo.setsda = set_data; - chan->algo.setscl = set_clock; - chan->algo.getsda = get_data; - chan->algo.getscl = get_clock; - chan->algo.udelay = I2C_RISEFALL_TIME; - chan->algo.timeout = usecs_to_jiffies(2200); - chan->algo.data = chan; - - i2c_set_adapdata(&chan->adapter, chan); - - if (i2c_bit_add_bus(&chan->adapter)) + snprintf(gpio->adapter.name, I2C_NAME_SIZE, "GPIO %d", pin); + gpio->adapter.owner = THIS_MODULE; + gpio->adapter.algo_data = &gpio->algo; + gpio->adapter.dev.parent = &dev_priv->dev->pdev->dev; + gpio->algo.setsda = set_data; + gpio->algo.setscl = set_clock; + gpio->algo.getsda = get_data; + gpio->algo.getscl = get_clock; + gpio->algo.udelay = I2C_RISEFALL_TIME; + gpio->algo.timeout = usecs_to_jiffies(2200); + gpio->algo.data = gpio; + + if (i2c_bit_add_bus(&gpio->adapter)) goto out_free; - intel_i2c_reset_gmbus(dev); + intel_i2c_reset(dev_priv->dev); /* JJJ: raise SCL and SDA? */ - intel_i2c_quirk_set(dev, true); - set_data(chan, 1); + intel_i2c_quirk_set(dev_priv, true); + set_data(gpio, 1); udelay(I2C_RISEFALL_TIME); - set_clock(chan, 1); + set_clock(gpio, 1); udelay(I2C_RISEFALL_TIME); - intel_i2c_quirk_set(dev, false); + intel_i2c_quirk_set(dev_priv, false); - return &chan->adapter; + return &gpio->adapter; out_free: - kfree(chan); + kfree(gpio); return NULL; } +static int +quirk_i2c_transfer(struct drm_i915_private *dev_priv, + struct i2c_adapter *adapter, + struct i2c_msg *msgs, + int num) +{ + int ret; + + intel_i2c_reset(dev_priv->dev); + + intel_i2c_quirk_set(dev_priv, true); + ret = i2c_transfer(adapter, msgs, num); + intel_i2c_quirk_set(dev_priv, false); + + return ret; +} + +static int +gmbus_xfer(struct i2c_adapter *adapter, + struct i2c_msg *msgs, + int num) +{ + struct intel_gmbus *bus = container_of(adapter, + struct intel_gmbus, + adapter); + struct drm_i915_private *dev_priv = adapter->algo_data; + int i, speed, reg_offset; + + if (bus->force_bitbanging) + return quirk_i2c_transfer(dev_priv, bus->force_bitbanging, msgs, num); + + reg_offset = HAS_PCH_SPLIT(dev_priv->dev) ? PCH_GMBUS0 - GMBUS0 : 0; + + speed = GMBUS_RATE_100KHZ; + if (INTEL_INFO(dev_priv->dev)->gen > 4 || IS_G4X(dev_priv->dev)) { + if (bus->pin == GMBUS_PORT_DPB) /* SDVO only? */ + speed = GMBUS_RATE_1MHZ; + else + speed = GMBUS_RATE_400KHZ; + } + I915_WRITE(GMBUS0 + reg_offset, speed | bus->pin); + + for (i = 0; i < num; i++) { + u16 len = msgs[i].len; + u8 *buf = msgs[i].buf; + + if (msgs[i].flags & I2C_M_RD) { + I915_WRITE(GMBUS1 + reg_offset, + GMBUS_CYCLE_WAIT | (i + 1 == num ? GMBUS_CYCLE_STOP : 0) | + (len << GMBUS_BYTE_COUNT_SHIFT) | + (msgs[i].addr << GMBUS_SLAVE_ADDR_SHIFT) | + GMBUS_SLAVE_READ | GMBUS_SW_RDY); + do { + u32 val, loop = 0; + + if (wait_for(I915_READ(GMBUS2 + reg_offset) & (GMBUS_SATOER | GMBUS_HW_RDY), 50)) + goto timeout; + if (I915_READ(GMBUS2 + reg_offset) & GMBUS_SATOER) + return 0; + + val = I915_READ(GMBUS3 + reg_offset); + do { + *buf++ = val & 0xff; + val >>= 8; + } while (--len && ++loop < 4); + } while (len); + } else { + u32 val = 0, loop = 0; + + BUG_ON(msgs[i].len > 4); + + do { + val |= *buf++ << (loop*8); + } while (--len && +loop < 4); + + I915_WRITE(GMBUS3 + reg_offset, val); + I915_WRITE(GMBUS1 + reg_offset, + (i + 1 == num ? GMBUS_CYCLE_STOP : GMBUS_CYCLE_WAIT ) | + (msgs[i].len << GMBUS_BYTE_COUNT_SHIFT) | + (msgs[i].addr << GMBUS_SLAVE_ADDR_SHIFT) | + GMBUS_SLAVE_WRITE | GMBUS_SW_RDY); + } + + if (i + 1 < num && wait_for(I915_READ(GMBUS2 + reg_offset) & (GMBUS_SATOER | GMBUS_HW_WAIT_PHASE), 50)) + goto timeout; + if (I915_READ(GMBUS2 + reg_offset) & GMBUS_SATOER) + return 0; + } + + return num; + +timeout: + DRM_INFO("GMBUS timed out, falling back to bit banging on pin %d\n", bus->pin); + /* Hardware may not support GMBUS over these pins? Try GPIO bitbanging instead. */ + bus->force_bitbanging = intel_gpio_create(dev_priv, bus->pin); + if (!bus->force_bitbanging) + return -ENOMEM; + + return quirk_i2c_transfer(dev_priv, bus->force_bitbanging, msgs, num); +} + +static u32 gmbus_func(struct i2c_adapter *adapter) +{ + return (I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL | + /* I2C_FUNC_10BIT_ADDR | */ + I2C_FUNC_SMBUS_READ_BLOCK_DATA | + I2C_FUNC_SMBUS_BLOCK_PROC_CALL); +} + +static const struct i2c_algorithm gmbus_algorithm = { + .master_xfer = gmbus_xfer, + .functionality = gmbus_func +}; + /** - * intel_i2c_destroy - unregister and free i2c bus resources - * @output: channel to free - * - * Unregister the adapter from the i2c layer, then free the structure. + * intel_gmbus_setup - instantiate all Intel i2c GMBuses + * @dev: DRM device */ -void intel_i2c_destroy(struct i2c_adapter *adapter) +int intel_setup_gmbus(struct drm_device *dev) +{ + static const char *names[] = { + "disabled", + "ssc", + "vga", + "panel", + "dpc", + "dpb", + "dpd", + "reserved" + }; + struct drm_i915_private *dev_priv = dev->dev_private; + int ret, i; + + dev_priv->gmbus = kcalloc(sizeof(struct intel_gmbus), GMBUS_NUM_PORTS, + GFP_KERNEL); + if (dev_priv->gmbus == NULL) + return -ENOMEM; + + for (i = 0; i < GMBUS_NUM_PORTS; i++) { + struct intel_gmbus *bus = &dev_priv->gmbus[i]; + + bus->adapter.owner = THIS_MODULE; + bus->adapter.class = I2C_CLASS_DDC; + snprintf(bus->adapter.name, + I2C_NAME_SIZE, + "gmbus %s", + names[i]); + + bus->adapter.dev.parent = &dev->pdev->dev; + bus->adapter.algo_data = dev_priv; + + bus->adapter.algo = &gmbus_algorithm; + ret = i2c_add_adapter(&bus->adapter); + if (ret) + goto err; + + bus->pin = i; + } + + intel_i2c_reset(dev_priv->dev); + + return 0; + +err: + while (--i) { + struct intel_gmbus *bus = &dev_priv->gmbus[i]; + i2c_del_adapter(&bus->adapter); + } + kfree(dev_priv->gmbus); + dev_priv->gmbus = NULL; + return ret; +} + +void intel_teardown_gmbus(struct drm_device *dev) { - struct intel_i2c_chan *chan; + struct drm_i915_private *dev_priv = dev->dev_private; + int i; - if (!adapter) + if (dev_priv->gmbus == NULL) return; - chan = container_of(adapter, - struct intel_i2c_chan, - adapter); - i2c_del_adapter(&chan->adapter); - kfree(chan); + for (i = 0; i < GMBUS_NUM_PORTS; i++) { + struct intel_gmbus *bus = &dev_priv->gmbus[i]; + if (bus->force_bitbanging) { + i2c_del_adapter(bus->force_bitbanging); + kfree(bus->force_bitbanging); + } + i2c_del_adapter(&bus->adapter); + } + + kfree(dev_priv->gmbus); + dev_priv->gmbus = NULL; } diff --git a/drivers/gpu/drm/i915/intel_lvds.c b/drivers/gpu/drm/i915/intel_lvds.c index 2ff4a5cb..9177c17 100644 --- a/drivers/gpu/drm/i915/intel_lvds.c +++ b/drivers/gpu/drm/i915/intel_lvds.c @@ -474,11 +474,12 @@ static int intel_lvds_get_modes(struct drm_connector *connector) { struct intel_lvds *intel_lvds = intel_attached_lvds(connector); struct drm_device *dev = connector->dev; + struct drm_i915_private *dev_priv = dev->dev_private; struct drm_display_mode *mode; if (intel_lvds->edid_good) { int ret = intel_ddc_get_modes(connector, - intel_lvds->base.ddc_bus); + &dev_priv->gmbus[GMBUS_PORT_PANEL].adapter); if (ret) return ret; } @@ -898,21 +899,12 @@ void intel_lvds_init(struct drm_device *dev) * if closed, act like it's not there for now */ - /* Set up the DDC bus. */ - intel_encoder->ddc_bus = intel_i2c_create(intel_encoder, - gpio, "LVDSDDC_C"); - if (!intel_encoder->ddc_bus) { - dev_printk(KERN_ERR, &dev->pdev->dev, "DDC bus registration " - "failed.\n"); - goto failed; - } - /* * Attempt to get the fixed panel mode from DDC. Assume that the * preferred mode is the right one. */ intel_lvds->edid_good = true; - if (!intel_ddc_get_modes(connector, intel_encoder->ddc_bus)) + if (!intel_ddc_get_modes(connector, &dev_priv->gmbus[GMBUS_PORT_PANEL].adapter)) intel_lvds->edid_good = false; if (!intel_lvds->edid_good) { @@ -999,8 +991,6 @@ out: failed: DRM_DEBUG_KMS("No LVDS modes found, disabling.\n"); - if (intel_encoder->ddc_bus) - intel_i2c_destroy(intel_encoder->ddc_bus); drm_connector_cleanup(connector); drm_encoder_cleanup(encoder); kfree(intel_lvds); diff --git a/drivers/gpu/drm/i915/intel_modes.c b/drivers/gpu/drm/i915/intel_modes.c index 1138aa9..f70b7cf 100644 --- a/drivers/gpu/drm/i915/intel_modes.c +++ b/drivers/gpu/drm/i915/intel_modes.c @@ -1,6 +1,6 @@ /* * Copyright (c) 2007 Dave Airlie - * Copyright (c) 2007 Intel Corporation + * Copyright (c) 2007, 2010 Intel Corporation * Jesse Barnes * * Permission is hereby granted, free of charge, to any person obtaining a @@ -34,11 +34,11 @@ * intel_ddc_probe * */ -bool intel_ddc_probe(struct intel_encoder *intel_encoder) +bool intel_ddc_probe(struct intel_encoder *intel_encoder, int ddc_bus) { + struct drm_i915_private *dev_priv = intel_encoder->base.dev->dev_private; u8 out_buf[] = { 0x0, 0x0}; u8 buf[2]; - int ret; struct i2c_msg msgs[] = { { .addr = 0x50, @@ -54,13 +54,7 @@ bool intel_ddc_probe(struct intel_encoder *intel_encoder) } }; - intel_i2c_quirk_set(intel_encoder->base.dev, true); - ret = i2c_transfer(intel_encoder->ddc_bus, msgs, 2); - intel_i2c_quirk_set(intel_encoder->base.dev, false); - if (ret == 2) - return true; - - return false; + return i2c_transfer(&dev_priv->gmbus[ddc_bus].adapter, msgs, 2) == 2; } /** @@ -76,9 +70,7 @@ int intel_ddc_get_modes(struct drm_connector *connector, struct edid *edid; int ret = 0; - intel_i2c_quirk_set(connector->dev, true); edid = drm_get_edid(connector, adapter); - intel_i2c_quirk_set(connector->dev, false); if (edid) { drm_mode_connector_update_edid_property(connector, edid); ret = drm_add_edid_modes(connector, edid); diff --git a/drivers/gpu/drm/i915/intel_sdvo.c b/drivers/gpu/drm/i915/intel_sdvo.c index f7030e4..2b3b475 100644 --- a/drivers/gpu/drm/i915/intel_sdvo.c +++ b/drivers/gpu/drm/i915/intel_sdvo.c @@ -65,6 +65,7 @@ static const char *tv_format_names[] = { struct intel_sdvo { struct intel_encoder base; + struct i2c_adapter *i2c; u8 slave_addr; /* Register for the SDVO device: SDVOB or SDVOC */ @@ -264,7 +265,7 @@ static bool intel_sdvo_read_byte(struct intel_sdvo *intel_sdvo, u8 addr, u8 *ch) }; int ret; - if ((ret = i2c_transfer(intel_sdvo->base.i2c_bus, msgs, 2)) == 2) + if ((ret = i2c_transfer(intel_sdvo->i2c, msgs, 2)) == 2) { *ch = buf[0]; return true; @@ -286,7 +287,7 @@ static bool intel_sdvo_write_byte(struct intel_sdvo *intel_sdvo, int addr, u8 ch } }; - return i2c_transfer(intel_sdvo->base.i2c_bus, msgs, 1) == 1; + return i2c_transfer(intel_sdvo->i2c, msgs, 1) == 1; } #define SDVO_CMD_NAME_ENTRY(cmd) {cmd, #cmd} @@ -566,7 +567,7 @@ static int intel_sdvo_set_control_bus_switch(struct intel_sdvo *intel_sdvo, ret_value[0] = 0; ret_value[1] = 0; - ret = i2c_transfer(intel_sdvo->base.i2c_bus, msgs, 3); + ret = i2c_transfer(intel_sdvo->i2c, msgs, 3); if (ret < 0) return ret; if (ret != 3) { @@ -1375,6 +1376,19 @@ intel_sdvo_multifunc_encoder(struct intel_sdvo *intel_sdvo) return (caps > 1); } +static struct edid * +intel_sdvo_get_edid(struct drm_connector *connector, int ddc) +{ + struct intel_sdvo *intel_sdvo = intel_attached_sdvo(connector); + int ret; + + ret = intel_sdvo_set_control_bus_switch(intel_sdvo, ddc); + if (ret) + return NULL; + + return drm_get_edid(connector, intel_sdvo->i2c); +} + static struct drm_connector * intel_find_analog_connector(struct drm_device *dev) { @@ -1418,28 +1432,12 @@ intel_analog_is_connected(struct drm_device *dev) static struct edid * intel_sdvo_get_analog_edid(struct drm_connector *connector) { - struct intel_encoder *encoder = intel_attached_encoder(connector); - struct drm_device *dev = connector->dev; - struct i2c_adapter *ddc; - struct edid *edid; - u32 ddc_reg; - - if (!intel_analog_is_connected(dev)) - return NULL; - - if (HAS_PCH_SPLIT(dev)) - ddc_reg = PCH_GPIOA; - else - ddc_reg = GPIOA; + struct drm_i915_private *dev_priv = connector->dev->dev_private; - ddc = intel_i2c_create(encoder, ddc_reg, "SDVO/VGA DDC BUS"); - if (ddc == NULL) + if (!intel_analog_is_connected(connector->dev)) return NULL; - edid = drm_get_edid(connector, ddc); - intel_i2c_destroy(ddc); - - return edid; + return drm_get_edid(connector, &dev_priv->gmbus[dev_priv->crt_ddc_pin].adapter); } enum drm_connector_status @@ -1449,28 +1447,26 @@ intel_sdvo_hdmi_sink_detect(struct drm_connector *connector) enum drm_connector_status status; struct edid *edid; - edid = drm_get_edid(connector, intel_sdvo->base.ddc_bus); + edid = intel_sdvo_get_edid(connector, intel_sdvo->ddc_bus); if (edid == NULL && intel_sdvo_multifunc_encoder(intel_sdvo)) { - u8 saved_ddc = intel_sdvo->ddc_bus, ddc; + u8 ddc; /* * Don't use the 1 as the argument of DDC bus switch to get * the EDID. It is used for SDVO SPD ROM. */ for (ddc = intel_sdvo->ddc_bus >> 1; ddc > 1; ddc >>= 1) { - intel_sdvo->ddc_bus = ddc; - edid = drm_get_edid(connector, intel_sdvo->base.ddc_bus); - if (edid) + edid = intel_sdvo_get_edid(connector, ddc); + if (edid) { + /* + * If we found the EDID on the other bus, + * assume that is the correct DDC bus. + */ + intel_sdvo->ddc_bus = ddc; break; + } } - - /* - * If we found the EDID on the other bus, maybe that is the - * correct DDC bus. - */ - if (edid == NULL) - intel_sdvo->ddc_bus = saved_ddc; } /* @@ -1546,12 +1542,9 @@ static void intel_sdvo_get_ddc_modes(struct drm_connector *connector) { struct intel_sdvo *intel_sdvo = intel_attached_sdvo(connector); struct edid *edid; - int num_modes; /* set the bus switch and get the modes */ - num_modes = intel_ddc_get_modes(connector, intel_sdvo->base.ddc_bus); - if (num_modes) - return; + edid = intel_sdvo_get_edid(connector, intel_sdvo->ddc_bus); /* * Mac mini hack. On this device, the DVI-I connector shares one DDC @@ -1559,7 +1552,9 @@ static void intel_sdvo_get_ddc_modes(struct drm_connector *connector) * DDC fails, check to see if the analog output is disconnected, in * which case we'll look there for the digital DDC data. */ - edid = intel_sdvo_get_analog_edid(connector); + if (edid == NULL) + edid = intel_sdvo_get_analog_edid(connector); + if (edid != NULL) { drm_mode_connector_update_edid_property(connector, edid); drm_add_edid_modes(connector, edid); @@ -1678,7 +1673,7 @@ static void intel_sdvo_get_lvds_modes(struct drm_connector *connector) * Assume that the preferred modes are * arranged in priority order. */ - intel_ddc_get_modes(connector, intel_sdvo->base.ddc_bus); + intel_ddc_get_modes(connector, intel_sdvo->i2c); if (list_empty(&connector->probed_modes) == false) goto end; @@ -2004,30 +1999,6 @@ intel_sdvo_get_digital_encoding_mode(struct intel_sdvo *intel_sdvo, int device) &intel_sdvo->is_hdmi, 1); } -static int intel_sdvo_master_xfer(struct i2c_adapter *i2c_adap, - struct i2c_msg msgs[], int num) -{ - struct intel_sdvo *intel_sdvo; - const struct i2c_algorithm *algo; - int ret; - - intel_sdvo = container_of(i2c_adap->algo_data, - struct intel_sdvo, - base); - algo = intel_sdvo->base.i2c_bus->algo; - - ret = intel_sdvo_set_control_bus_switch(intel_sdvo, - intel_sdvo->ddc_bus); - if (ret) - return ret; - - return algo->master_xfer(i2c_adap, msgs, num); -} - -static struct i2c_algorithm intel_sdvo_i2c_bit_algo = { - .master_xfer = intel_sdvo_master_xfer, -}; - static u8 intel_sdvo_get_slave_addr(struct drm_device *dev, int sdvo_reg) { @@ -2540,9 +2511,7 @@ bool intel_sdvo_init(struct drm_device *dev, int sdvo_reg) struct drm_i915_private *dev_priv = dev->dev_private; struct intel_encoder *intel_encoder; struct intel_sdvo *intel_sdvo; - u8 ch[0x40]; int i; - u32 i2c_reg, ddc_reg; intel_sdvo = kzalloc(sizeof(struct intel_sdvo), GFP_KERNEL); if (!intel_sdvo) @@ -2555,82 +2524,49 @@ bool intel_sdvo_init(struct drm_device *dev, int sdvo_reg) /* encoder type will be decided later */ drm_encoder_init(dev, &intel_encoder->base, &intel_sdvo_enc_funcs, 0); - if (HAS_PCH_SPLIT(dev)) { - i2c_reg = PCH_GPIOE; - ddc_reg = PCH_GPIOE; - } else { - i2c_reg = GPIOE; - ddc_reg = GPIOE; - } - - /* setup the DDC bus. */ - if (IS_SDVOB(sdvo_reg)) - intel_encoder->i2c_bus = - intel_i2c_create(intel_encoder, - i2c_reg, "SDVOCTRL_E for SDVOB"); - else - intel_encoder->i2c_bus = - intel_i2c_create(intel_encoder, - i2c_reg, "SDVOCTRL_E for SDVOC"); - - if (!intel_encoder->i2c_bus) - goto err_inteloutput; + intel_sdvo->i2c = &dev_priv->gmbus[GMBUS_PORT_DPB].adapter; intel_sdvo->slave_addr = intel_sdvo_get_slave_addr(dev, sdvo_reg); - /* Save the bit-banging i2c functionality for use by the DDC wrapper */ - intel_sdvo_i2c_bit_algo.functionality = intel_encoder->i2c_bus->algo->functionality; - /* Read the regs to test if we can talk to the device */ for (i = 0; i < 0x40; i++) { - if (!intel_sdvo_read_byte(intel_sdvo, i, &ch[i])) { + u8 byte; + + if (!intel_sdvo_read_byte(intel_sdvo, i, &byte)) { DRM_DEBUG_KMS("No SDVO device found on SDVO%c\n", IS_SDVOB(sdvo_reg) ? 'B' : 'C'); - goto err_i2c; + goto err; } } - /* setup the DDC bus. */ - if (IS_SDVOB(sdvo_reg)) { - intel_encoder->ddc_bus = - intel_i2c_create(intel_encoder, - ddc_reg, "SDVOB DDC BUS"); + if (IS_SDVOB(sdvo_reg)) dev_priv->hotplug_supported_mask |= SDVOB_HOTPLUG_INT_STATUS; - } else { - intel_encoder->ddc_bus = - intel_i2c_create(intel_encoder, - ddc_reg, "SDVOC DDC BUS"); + else dev_priv->hotplug_supported_mask |= SDVOC_HOTPLUG_INT_STATUS; - } - if (intel_encoder->ddc_bus == NULL) - goto err_i2c; - - /* Wrap with our custom algo which switches to DDC mode */ - intel_encoder->ddc_bus->algo = &intel_sdvo_i2c_bit_algo; drm_encoder_helper_add(&intel_encoder->base, &intel_sdvo_helper_funcs); /* In default case sdvo lvds is false */ if (!intel_sdvo_get_capabilities(intel_sdvo, &intel_sdvo->caps)) - goto err_i2c; + goto err; if (intel_sdvo_output_setup(intel_sdvo, intel_sdvo->caps.output_flags) != true) { DRM_DEBUG_KMS("SDVO output failed to setup on SDVO%c\n", IS_SDVOB(sdvo_reg) ? 'B' : 'C'); - goto err_i2c; + goto err; } intel_sdvo_select_ddc_bus(dev_priv, intel_sdvo, sdvo_reg); /* Set the input timing to the screen. Assume always input 0. */ if (!intel_sdvo_set_target_input(intel_sdvo)) - goto err_i2c; + goto err; if (!intel_sdvo_get_input_pixel_clock_range(intel_sdvo, &intel_sdvo->pixel_clock_min, &intel_sdvo->pixel_clock_max)) - goto err_i2c; + goto err; DRM_DEBUG_KMS("%s device VID/DID: %02X:%02X.%02X, " "clock range %dMHz - %dMHz, " @@ -2650,12 +2586,7 @@ bool intel_sdvo_init(struct drm_device *dev, int sdvo_reg) (SDVO_OUTPUT_TMDS1 | SDVO_OUTPUT_RGB1) ? 'Y' : 'N'); return true; -err_i2c: - if (intel_encoder->ddc_bus != NULL) - intel_i2c_destroy(intel_encoder->ddc_bus); - if (intel_encoder->i2c_bus != NULL) - intel_i2c_destroy(intel_encoder->i2c_bus); -err_inteloutput: +err: drm_encoder_cleanup(&intel_encoder->base); kfree(intel_sdvo); -- cgit v1.1 From 219adae138513bae20b256f1946b9cb3b75ca05c Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Thu, 16 Sep 2010 23:05:10 +0100 Subject: drm/i915: Cache LVDS EDID We assume that the panel is permenantly connected and that the EDID data is consistent from boot, so simply cache the whole EDID for the panel. Signed-off-by: Chris Wilson --- drivers/gpu/drm/i915/intel_lvds.c | 19 ++++++++----------- 1 file changed, 8 insertions(+), 11 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_lvds.c b/drivers/gpu/drm/i915/intel_lvds.c index f6a72cb..5666e89 100644 --- a/drivers/gpu/drm/i915/intel_lvds.c +++ b/drivers/gpu/drm/i915/intel_lvds.c @@ -44,7 +44,7 @@ struct intel_lvds { struct intel_encoder base; - bool edid_good; + struct edid *edid; int fitting_mode; u32 pfit_control; @@ -475,14 +475,12 @@ static int intel_lvds_get_modes(struct drm_connector *connector) { struct intel_lvds *intel_lvds = intel_attached_lvds(connector); struct drm_device *dev = connector->dev; - struct drm_i915_private *dev_priv = dev->dev_private; struct drm_display_mode *mode; - if (intel_lvds->edid_good) { - int ret = intel_ddc_get_modes(connector, - &dev_priv->gmbus[GMBUS_PORT_PANEL].adapter); - if (ret) - return ret; + if (intel_lvds->edid) { + drm_mode_connector_update_edid_property(connector, + intel_lvds->edid); + return drm_add_edid_modes(connector, intel_lvds->edid); } mode = drm_mode_duplicate(dev, intel_lvds->fixed_mode); @@ -906,11 +904,10 @@ void intel_lvds_init(struct drm_device *dev) * Attempt to get the fixed panel mode from DDC. Assume that the * preferred mode is the right one. */ - intel_lvds->edid_good = true; - if (!intel_ddc_get_modes(connector, &dev_priv->gmbus[GMBUS_PORT_PANEL].adapter)) - intel_lvds->edid_good = false; + intel_lvds->edid = drm_get_edid(connector, + &dev_priv->gmbus[GMBUS_PORT_PANEL].adapter); - if (!intel_lvds->edid_good) { + if (!intel_lvds->edid) { /* Didn't get an EDID, so * Set wide sync ranges so we get all modes * handed to valid_mode for checking -- cgit v1.1 From a6c45cf013a57e32ddae43dd4ac911eb4a3919fd Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Fri, 17 Sep 2010 00:32:17 +0100 Subject: drm/i915: INTEL_INFO->gen supercedes i8xx, i9xx, i965g Avoid confusion between i965g meaning broadwater and the gen4+ chipset families. Signed-off-by: Chris Wilson --- drivers/gpu/drm/i915/i915_debugfs.c | 11 ++--- drivers/gpu/drm/i915/i915_dma.c | 28 +++++------ drivers/gpu/drm/i915/i915_drv.c | 84 ++++++++++++++++----------------- drivers/gpu/drm/i915/i915_drv.h | 18 ++----- drivers/gpu/drm/i915/i915_gem.c | 29 ++++++++---- drivers/gpu/drm/i915/i915_gem_tiling.c | 30 ++++++------ drivers/gpu/drm/i915/i915_irq.c | 29 ++++++------ drivers/gpu/drm/i915/i915_suspend.c | 24 +++++----- drivers/gpu/drm/i915/intel_crt.c | 8 ++-- drivers/gpu/drm/i915/intel_display.c | 74 ++++++++++++++--------------- drivers/gpu/drm/i915/intel_fb.c | 4 +- drivers/gpu/drm/i915/intel_lvds.c | 10 ++-- drivers/gpu/drm/i915/intel_overlay.c | 29 ++++++------ drivers/gpu/drm/i915/intel_panel.c | 4 +- drivers/gpu/drm/i915/intel_ringbuffer.c | 8 ++-- drivers/gpu/drm/i915/intel_sdvo.c | 4 +- drivers/gpu/drm/i915/intel_tv.c | 4 +- 17 files changed, 197 insertions(+), 201 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_debugfs.c b/drivers/gpu/drm/i915/i915_debugfs.c index fb5c2a6..361a825 100644 --- a/drivers/gpu/drm/i915/i915_debugfs.c +++ b/drivers/gpu/drm/i915/i915_debugfs.c @@ -58,13 +58,9 @@ static int i915_capabilities(struct seq_file *m, void *data) seq_printf(m, "gen: %d\n", info->gen); #define B(x) seq_printf(m, #x ": %s\n", yesno(info->x)) B(is_mobile); - B(is_i8xx); B(is_i85x); B(is_i915g); - B(is_i9xx); B(is_i945gm); - B(is_i965g); - B(is_i965gm); B(is_g33); B(need_gfx_hws); B(is_g4x); @@ -79,6 +75,7 @@ static int i915_capabilities(struct seq_file *m, void *data) B(cursor_needs_physical); B(has_overlay); B(overlay_needs_physical); + B(supports_tv); #undef B return 0; @@ -473,7 +470,7 @@ static int i915_ringbuffer_info(struct seq_file *m, void *data) seq_printf(m, "RingHead : %08x\n", head); seq_printf(m, "RingTail : %08x\n", tail); seq_printf(m, "RingSize : %08lx\n", dev_priv->render_ring.size); - seq_printf(m, "Acthd : %08x\n", I915_READ(IS_I965G(dev) ? ACTHD_I965 : ACTHD)); + seq_printf(m, "Acthd : %08x\n", I915_READ(INTEL_INFO(dev)->gen >= 4 ? ACTHD_I965 : ACTHD)); return 0; } @@ -535,7 +532,7 @@ static int i915_error_state(struct seq_file *m, void *unused) seq_printf(m, " IPEHR: 0x%08x\n", error->ipehr); seq_printf(m, " INSTDONE: 0x%08x\n", error->instdone); seq_printf(m, " ACTHD: 0x%08x\n", error->acthd); - if (IS_I965G(dev)) { + if (INTEL_INFO(dev)->gen >= 4) { seq_printf(m, " INSTPS: 0x%08x\n", error->instps); seq_printf(m, " INSTDONE1: 0x%08x\n", error->instdone1); } @@ -757,7 +754,7 @@ static int i915_sr_status(struct seq_file *m, void *unused) if (IS_IRONLAKE(dev)) sr_enabled = I915_READ(WM1_LP_ILK) & WM1_LP_SR_EN; - else if (IS_I965GM(dev) || IS_I945G(dev) || IS_I945GM(dev)) + else if (IS_CRESTLINE(dev) || IS_I945G(dev) || IS_I945GM(dev)) sr_enabled = I915_READ(FW_BLC_SELF) & FW_BLC_SELF_EN; else if (IS_I915GM(dev)) sr_enabled = I915_READ(INSTPM) & INSTPM_SELF_EN; diff --git a/drivers/gpu/drm/i915/i915_dma.c b/drivers/gpu/drm/i915/i915_dma.c index 39aaffe..9977a0a 100644 --- a/drivers/gpu/drm/i915/i915_dma.c +++ b/drivers/gpu/drm/i915/i915_dma.c @@ -63,7 +63,7 @@ static int i915_init_phys_hws(struct drm_device *dev) memset(dev_priv->render_ring.status_page.page_addr, 0, PAGE_SIZE); - if (IS_I965G(dev)) + if (INTEL_INFO(dev)->gen >= 4) dev_priv->dma_status_page |= (dev_priv->dma_status_page >> 28) & 0xf0; @@ -376,7 +376,7 @@ i915_emit_box(struct drm_device *dev, return -EINVAL; } - if (IS_I965G(dev)) { + if (INTEL_INFO(dev)->gen >= 4) { BEGIN_LP_RING(4); OUT_RING(GFX_OP_DRAWRECT_INFO_I965); OUT_RING((box.x1 & 0xffff) | (box.y1 << 16)); @@ -480,7 +480,7 @@ static int i915_dispatch_batchbuffer(struct drm_device * dev, if (!IS_I830(dev) && !IS_845G(dev)) { BEGIN_LP_RING(2); - if (IS_I965G(dev)) { + if (INTEL_INFO(dev)->gen >= 4) { OUT_RING(MI_BATCH_BUFFER_START | (2 << 6) | MI_BATCH_NON_SECURE_I965); OUT_RING(batch->start); } else { @@ -887,12 +887,12 @@ static int intel_alloc_mchbar_resource(struct drm_device *dev) { drm_i915_private_t *dev_priv = dev->dev_private; - int reg = IS_I965G(dev) ? MCHBAR_I965 : MCHBAR_I915; + int reg = INTEL_INFO(dev)->gen >= 4 ? MCHBAR_I965 : MCHBAR_I915; u32 temp_lo, temp_hi = 0; u64 mchbar_addr; int ret; - if (IS_I965G(dev)) + if (INTEL_INFO(dev)->gen >= 4) pci_read_config_dword(dev_priv->bridge_dev, reg + 4, &temp_hi); pci_read_config_dword(dev_priv->bridge_dev, reg, &temp_lo); mchbar_addr = ((u64)temp_hi << 32) | temp_lo; @@ -919,7 +919,7 @@ intel_alloc_mchbar_resource(struct drm_device *dev) return ret; } - if (IS_I965G(dev)) + if (INTEL_INFO(dev)->gen >= 4) pci_write_config_dword(dev_priv->bridge_dev, reg + 4, upper_32_bits(dev_priv->mch_res.start)); @@ -933,7 +933,7 @@ static void intel_setup_mchbar(struct drm_device *dev) { drm_i915_private_t *dev_priv = dev->dev_private; - int mchbar_reg = IS_I965G(dev) ? MCHBAR_I965 : MCHBAR_I915; + int mchbar_reg = INTEL_INFO(dev)->gen >= 4 ? MCHBAR_I965 : MCHBAR_I915; u32 temp; bool enabled; @@ -970,7 +970,7 @@ static void intel_teardown_mchbar(struct drm_device *dev) { drm_i915_private_t *dev_priv = dev->dev_private; - int mchbar_reg = IS_I965G(dev) ? MCHBAR_I965 : MCHBAR_I915; + int mchbar_reg = INTEL_INFO(dev)->gen >= 4 ? MCHBAR_I965 : MCHBAR_I915; u32 temp; if (dev_priv->mchbar_need_disable) { @@ -1012,11 +1012,11 @@ static unsigned long i915_gtt_to_phys(struct drm_device *dev, { unsigned long *gtt; unsigned long entry, phys; - int gtt_bar = IS_I9XX(dev) ? 0 : 1; + int gtt_bar = IS_GEN2(dev) ? 1 : 0; int gtt_offset, gtt_size; - if (IS_I965G(dev)) { - if (IS_G4X(dev) || IS_IRONLAKE(dev) || IS_GEN6(dev)) { + if (INTEL_INFO(dev)->gen >= 4) { + if (IS_G4X(dev) || INTEL_INFO(dev)->gen > 4) { gtt_offset = 2*1024*1024; gtt_size = 2*1024*1024; } else { @@ -1041,10 +1041,8 @@ static unsigned long i915_gtt_to_phys(struct drm_device *dev, DRM_DEBUG_DRIVER("GTT addr: 0x%08lx, PTE: 0x%08lx\n", gtt_addr, entry); /* Mask out these reserved bits on this hardware. */ - if (!IS_I9XX(dev) || IS_I915G(dev) || IS_I915GM(dev) || - IS_I945G(dev) || IS_I945GM(dev)) { + if (INTEL_INFO(dev)->gen < 4 && !IS_G33(dev)) entry &= ~PTE_ADDRESS_MASK_HIGH; - } /* If it's not a mapping type we know, then bail. */ if ((entry & PTE_MAPPING_TYPE_MASK) != PTE_MAPPING_TYPE_UNCACHED && @@ -1899,7 +1897,7 @@ int i915_driver_load(struct drm_device *dev, unsigned long flags) dev_priv->info = (struct intel_device_info *) flags; /* Add register map (needed for suspend/resume) */ - mmio_bar = IS_I9XX(dev) ? 0 : 1; + mmio_bar = IS_GEN2(dev) ? 1 : 0; base = pci_resource_start(dev->pdev, mmio_bar); size = pci_resource_len(dev->pdev, mmio_bar); diff --git a/drivers/gpu/drm/i915/i915_drv.c b/drivers/gpu/drm/i915/i915_drv.c index 13dca9d..87c6b5f 100644 --- a/drivers/gpu/drm/i915/i915_drv.c +++ b/drivers/gpu/drm/i915/i915_drv.c @@ -61,97 +61,101 @@ extern int intel_agp_enabled; .driver_data = (unsigned long) info } static const struct intel_device_info intel_i830_info = { - .gen = 2, .is_i8xx = 1, .is_mobile = 1, .cursor_needs_physical = 1, + .gen = 2, .is_mobile = 1, .cursor_needs_physical = 1, .has_overlay = 1, .overlay_needs_physical = 1, }; static const struct intel_device_info intel_845g_info = { - .gen = 2, .is_i8xx = 1, + .gen = 2, .has_overlay = 1, .overlay_needs_physical = 1, }; static const struct intel_device_info intel_i85x_info = { - .gen = 2, .is_i8xx = 1, .is_i85x = 1, .is_mobile = 1, + .gen = 2, .is_i85x = 1, .is_mobile = 1, .cursor_needs_physical = 1, .has_overlay = 1, .overlay_needs_physical = 1, }; static const struct intel_device_info intel_i865g_info = { - .gen = 2, .is_i8xx = 1, + .gen = 2, .has_overlay = 1, .overlay_needs_physical = 1, }; static const struct intel_device_info intel_i915g_info = { - .gen = 3, .is_i915g = 1, .is_i9xx = 1, .cursor_needs_physical = 1, + .gen = 3, .is_i915g = 1, .cursor_needs_physical = 1, .has_overlay = 1, .overlay_needs_physical = 1, }; static const struct intel_device_info intel_i915gm_info = { - .gen = 3, .is_i9xx = 1, .is_mobile = 1, + .gen = 3, .is_mobile = 1, .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, .is_i9xx = 1, .has_hotplug = 1, .cursor_needs_physical = 1, + .gen = 3, .has_hotplug = 1, .cursor_needs_physical = 1, .has_overlay = 1, .overlay_needs_physical = 1, }; static const struct intel_device_info intel_i945gm_info = { - .gen = 3, .is_i945gm = 1, .is_i9xx = 1, .is_mobile = 1, + .gen = 3, .is_i945gm = 1, .is_mobile = 1, .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, .is_i965g = 1, .is_i9xx = 1, + .gen = 4, .is_broadwater = 1, .has_hotplug = 1, .has_overlay = 1, }; static const struct intel_device_info intel_i965gm_info = { - .gen = 4, .is_crestline = 1, .is_i965g = 1, .is_i965gm = 1, .is_i9xx = 1, + .gen = 4, .is_crestline = 1, .is_mobile = 1, .has_fbc = 1, .has_rc6 = 1, .has_hotplug = 1, .has_overlay = 1, + .supports_tv = 1, }; static const struct intel_device_info intel_g33_info = { - .gen = 3, .is_g33 = 1, .is_i9xx = 1, + .gen = 3, .is_g33 = 1, .need_gfx_hws = 1, .has_hotplug = 1, .has_overlay = 1, }; static const struct intel_device_info intel_g45_info = { - .gen = 4, .is_i965g = 1, .is_g4x = 1, .is_i9xx = 1, .need_gfx_hws = 1, + .gen = 4, .is_g4x = 1, .need_gfx_hws = 1, .has_pipe_cxsr = 1, .has_hotplug = 1, }; static const struct intel_device_info intel_gm45_info = { - .gen = 4, .is_i965g = 1, .is_g4x = 1, .is_i9xx = 1, + .gen = 4, .is_g4x = 1, .is_mobile = 1, .need_gfx_hws = 1, .has_fbc = 1, .has_rc6 = 1, .has_pipe_cxsr = 1, .has_hotplug = 1, + .supports_tv = 1, }; static const struct intel_device_info intel_pineview_info = { - .gen = 3, .is_g33 = 1, .is_pineview = 1, .is_mobile = 1, .is_i9xx = 1, + .gen = 3, .is_g33 = 1, .is_pineview = 1, .is_mobile = 1, .need_gfx_hws = 1, .has_hotplug = 1, .has_overlay = 1, }; static const struct intel_device_info intel_ironlake_d_info = { - .gen = 5, .is_ironlake = 1, .is_i965g = 1, .is_i9xx = 1, + .gen = 5, .is_ironlake = 1, .need_gfx_hws = 1, .has_pipe_cxsr = 1, .has_hotplug = 1, }; static const struct intel_device_info intel_ironlake_m_info = { - .gen = 5, .is_ironlake = 1, .is_mobile = 1, .is_i965g = 1, .is_i9xx = 1, + .gen = 5, .is_ironlake = 1, .is_mobile = 1, .need_gfx_hws = 1, .has_fbc = 1, .has_rc6 = 1, .has_hotplug = 1, }; static const struct intel_device_info intel_sandybridge_d_info = { - .gen = 6, .is_i965g = 1, .is_i9xx = 1, + .gen = 6, .need_gfx_hws = 1, .has_hotplug = 1, }; static const struct intel_device_info intel_sandybridge_m_info = { - .gen = 6, .is_i965g = 1, .is_mobile = 1, .is_i9xx = 1, + .gen = 6, .is_mobile = 1, .need_gfx_hws = 1, .has_hotplug = 1, }; @@ -359,33 +363,27 @@ int i965_reset(struct drm_device *dev, u8 flags) if (need_display) i915_save_display(dev); - if (IS_I965G(dev) || IS_G4X(dev)) { - /* - * Set the domains we want to reset, then the reset bit (bit 0). - * Clear the reset bit after a while and wait for hardware status - * bit (bit 1) to be set - */ + /* + * Set the domains we want to reset, then the reset bit (bit 0). + * Clear the reset bit after a while and wait for hardware status + * bit (bit 1) to be set + */ + pci_read_config_byte(dev->pdev, GDRST, &gdrst); + pci_write_config_byte(dev->pdev, GDRST, gdrst | flags | ((flags == GDRST_FULL) ? 0x1 : 0x0)); + udelay(50); + pci_write_config_byte(dev->pdev, GDRST, gdrst & 0xfe); + + /* ...we don't want to loop forever though, 500ms should be plenty */ + timeout = jiffies + msecs_to_jiffies(500); + do { + udelay(100); pci_read_config_byte(dev->pdev, GDRST, &gdrst); - pci_write_config_byte(dev->pdev, GDRST, gdrst | flags | ((flags == GDRST_FULL) ? 0x1 : 0x0)); - udelay(50); - pci_write_config_byte(dev->pdev, GDRST, gdrst & 0xfe); - - /* ...we don't want to loop forever though, 500ms should be plenty */ - timeout = jiffies + msecs_to_jiffies(500); - do { - udelay(100); - pci_read_config_byte(dev->pdev, GDRST, &gdrst); - } while ((gdrst & 0x1) && time_after(timeout, jiffies)); - - if (gdrst & 0x1) { - WARN(true, "i915: Failed to reset chip\n"); - mutex_unlock(&dev->struct_mutex); - return -EIO; - } - } else { - DRM_ERROR("Error occurred. Don't know how to reset this chip.\n"); + } while ((gdrst & 0x1) && time_after(timeout, jiffies)); + + if (gdrst & 0x1) { + WARN(true, "i915: Failed to reset chip\n"); mutex_unlock(&dev->struct_mutex); - return -ENODEV; + return -EIO; } /* Ok, now get things going again... */ diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index cf08128..4b6aeb5 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -196,13 +196,9 @@ struct drm_i915_display_funcs { struct intel_device_info { u8 gen; u8 is_mobile : 1; - u8 is_i8xx : 1; u8 is_i85x : 1; u8 is_i915g : 1; - u8 is_i9xx : 1; u8 is_i945gm : 1; - u8 is_i965g : 1; - u8 is_i965gm : 1; u8 is_g33 : 1; u8 need_gfx_hws : 1; u8 is_g4x : 1; @@ -217,6 +213,7 @@ struct intel_device_info { u8 cursor_needs_physical : 1; u8 has_overlay : 1; u8 overlay_needs_physical : 1; + u8 supports_tv : 1; }; enum no_fbc_reason { @@ -1220,8 +1217,6 @@ static inline void i915_write(struct drm_i915_private *dev_priv, u32 reg, #define IS_I915GM(dev) ((dev)->pci_device == 0x2592) #define IS_I945G(dev) ((dev)->pci_device == 0x2772) #define IS_I945GM(dev) (INTEL_INFO(dev)->is_i945gm) -#define IS_I965G(dev) (INTEL_INFO(dev)->is_i965g) -#define IS_I965GM(dev) (INTEL_INFO(dev)->is_i965gm) #define IS_BROADWATER(dev) (INTEL_INFO(dev)->is_broadwater) #define IS_CRESTLINE(dev) (INTEL_INFO(dev)->is_crestline) #define IS_GM45(dev) ((dev)->pci_device == 0x2A42) @@ -1233,7 +1228,6 @@ static inline void i915_write(struct drm_i915_private *dev_priv, u32 reg, #define IS_IRONLAKE_D(dev) ((dev)->pci_device == 0x0042) #define IS_IRONLAKE_M(dev) ((dev)->pci_device == 0x0046) #define IS_IRONLAKE(dev) (INTEL_INFO(dev)->is_ironlake) -#define IS_I9XX(dev) (INTEL_INFO(dev)->is_i9xx) #define IS_MOBILE(dev) (INTEL_INFO(dev)->is_mobile) #define IS_GEN2(dev) (INTEL_INFO(dev)->gen == 2) @@ -1251,20 +1245,18 @@ static inline void i915_write(struct drm_i915_private *dev_priv, u32 reg, /* With the 945 and later, Y tiling got adjusted so that it was 32 128-byte * rows, which changed the alignment requirements and fence programming. */ -#define HAS_128_BYTE_Y_TILING(dev) (IS_I9XX(dev) && !(IS_I915G(dev) || \ +#define HAS_128_BYTE_Y_TILING(dev) (!IS_GEN2(dev) && !(IS_I915G(dev) || \ IS_I915GM(dev))) -#define SUPPORTS_DIGITAL_OUTPUTS(dev) (IS_I9XX(dev) && !IS_PINEVIEW(dev)) +#define SUPPORTS_DIGITAL_OUTPUTS(dev) (!IS_GEN2(dev) && !IS_PINEVIEW(dev)) #define SUPPORTS_INTEGRATED_HDMI(dev) (IS_G4X(dev) || IS_IRONLAKE(dev)) #define SUPPORTS_INTEGRATED_DP(dev) (IS_G4X(dev) || IS_IRONLAKE(dev)) #define SUPPORTS_EDP(dev) (IS_IRONLAKE_M(dev)) -#define SUPPORTS_TV(dev) (IS_I9XX(dev) && IS_MOBILE(dev) && \ - !IS_IRONLAKE(dev) && !IS_PINEVIEW(dev) && \ - !IS_GEN6(dev)) +#define SUPPORTS_TV(dev) (INTEL_INFO(dev)->supports_tv) #define I915_HAS_HOTPLUG(dev) (INTEL_INFO(dev)->has_hotplug) /* dsparb controlled by hw only */ #define DSPARB_HWCONTROL(dev) (IS_G4X(dev) || IS_IRONLAKE(dev)) -#define HAS_FW_BLC(dev) (IS_I9XX(dev) || IS_G4X(dev) || IS_IRONLAKE(dev)) +#define HAS_FW_BLC(dev) (INTEL_INFO(dev)->gen > 2) #define HAS_PIPE_CXSR(dev) (INTEL_INFO(dev)->has_pipe_cxsr) #define I915_HAS_FBC(dev) (INTEL_INFO(dev)->has_fbc) #define I915_HAS_RC6(dev) (INTEL_INFO(dev)->has_rc6) diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index 0355cd2..71a2723 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -1346,14 +1346,14 @@ i915_gem_get_gtt_alignment(struct drm_gem_object *obj) * Minimum alignment is 4k (GTT page size), but might be greater * if a fence register is needed for the object. */ - if (IS_I965G(dev) || obj_priv->tiling_mode == I915_TILING_NONE) + if (INTEL_INFO(dev)->gen >= 4 || obj_priv->tiling_mode == I915_TILING_NONE) return 4096; /* * Previous chips need to be aligned to the size of the smallest * fence register that can contain the object. */ - if (IS_I9XX(dev)) + if (INTEL_INFO(dev)->gen == 3) start = 1024*1024; else start = 512*1024; @@ -1660,7 +1660,7 @@ i915_retire_commands(struct drm_device *dev, struct intel_ring_buffer *ring) uint32_t flush_domains = 0; /* The sampler always gets flushed on i965 (sigh) */ - if (IS_I965G(dev)) + if (INTEL_INFO(dev)->gen >= 4) flush_domains |= I915_GEM_DOMAIN_SAMPLER; ring->flush(dev, ring, @@ -2443,7 +2443,7 @@ i915_gem_object_put_fence_reg(struct drm_gem_object *obj, * therefore we must wait for any outstanding access to complete * before clearing the fence. */ - if (!IS_I965G(dev)) { + if (INTEL_INFO(dev)->gen < 4) { int ret; ret = i915_gem_object_flush_gpu_write_domain(obj, true); @@ -3893,7 +3893,7 @@ i915_gem_execbuffer(struct drm_device *dev, void *data, exec2_list[i].relocs_ptr = exec_list[i].relocs_ptr; exec2_list[i].alignment = exec_list[i].alignment; exec2_list[i].offset = exec_list[i].offset; - if (!IS_I965G(dev)) + if (INTEL_INFO(dev)->gen < 4) exec2_list[i].flags = EXEC_OBJECT_NEEDS_FENCE; else exec2_list[i].flags = 0; @@ -4614,21 +4614,30 @@ i915_gem_load(struct drm_device *dev) if (!drm_core_check_feature(dev, DRIVER_MODESET)) dev_priv->fence_reg_start = 3; - if (IS_I965G(dev) || IS_I945G(dev) || IS_I945GM(dev) || IS_G33(dev)) + if (INTEL_INFO(dev)->gen >= 4 || IS_I945G(dev) || IS_I945GM(dev) || IS_G33(dev)) dev_priv->num_fence_regs = 16; else dev_priv->num_fence_regs = 8; /* Initialize fence registers to zero */ - if (IS_I965G(dev)) { + switch (INTEL_INFO(dev)->gen) { + case 6: + for (i = 0; i < 16; i++) + I915_WRITE64(FENCE_REG_SANDYBRIDGE_0 + (i * 8), 0); + break; + case 5: + case 4: for (i = 0; i < 16; i++) I915_WRITE64(FENCE_REG_965_0 + (i * 8), 0); - } else { - for (i = 0; i < 8; i++) - I915_WRITE(FENCE_REG_830_0 + (i * 4), 0); + break; + case 3: if (IS_I945G(dev) || IS_I945GM(dev) || IS_G33(dev)) for (i = 0; i < 8; i++) I915_WRITE(FENCE_REG_945_8 + (i * 4), 0); + case 2: + for (i = 0; i < 8; i++) + I915_WRITE(FENCE_REG_830_0 + (i * 4), 0); + break; } i915_gem_detect_bit_6_swizzle(dev); init_waitqueue_head(&dev_priv->pending_flip_queue); diff --git a/drivers/gpu/drm/i915/i915_gem_tiling.c b/drivers/gpu/drm/i915/i915_gem_tiling.c index caef7ff..b09b157 100644 --- a/drivers/gpu/drm/i915/i915_gem_tiling.c +++ b/drivers/gpu/drm/i915/i915_gem_tiling.c @@ -98,7 +98,7 @@ i915_gem_detect_bit_6_swizzle(struct drm_device *dev) */ swizzle_x = I915_BIT_6_SWIZZLE_9_10; swizzle_y = I915_BIT_6_SWIZZLE_9; - } else if (!IS_I9XX(dev)) { + } else if (IS_GEN2(dev)) { /* As far as we know, the 865 doesn't have these bit 6 * swizzling issues. */ @@ -190,19 +190,19 @@ i915_tiling_ok(struct drm_device *dev, int stride, int size, int tiling_mode) if (tiling_mode == I915_TILING_NONE) return true; - if (!IS_I9XX(dev) || + if (IS_GEN2(dev) || (tiling_mode == I915_TILING_Y && HAS_128_BYTE_Y_TILING(dev))) tile_width = 128; else tile_width = 512; /* check maximum stride & object size */ - if (IS_I965G(dev)) { + if (INTEL_INFO(dev)->gen >= 4) { /* i965 stores the end address of the gtt mapping in the fence * reg, so dont bother to check the size */ if (stride / 128 > I965_FENCE_MAX_PITCH_VAL) return false; - } else if (IS_GEN3(dev) || IS_GEN2(dev)) { + } else { if (stride > 8192) return false; @@ -216,7 +216,7 @@ i915_tiling_ok(struct drm_device *dev, int stride, int size, int tiling_mode) } /* 965+ just needs multiples of tile width */ - if (IS_I965G(dev)) { + if (INTEL_INFO(dev)->gen >= 4) { if (stride & (tile_width - 1)) return false; return true; @@ -244,16 +244,18 @@ i915_gem_object_fence_offset_ok(struct drm_gem_object *obj, int tiling_mode) if (tiling_mode == I915_TILING_NONE) return true; - if (!IS_I965G(dev)) { - if (obj_priv->gtt_offset & (obj->size - 1)) + if (INTEL_INFO(dev)->gen >= 4) + return true; + + if (obj_priv->gtt_offset & (obj->size - 1)) + return false; + + if (IS_GEN3(dev)) { + if (obj_priv->gtt_offset & ~I915_FENCE_START_MASK) + return false; + } else { + if (obj_priv->gtt_offset & ~I830_FENCE_START_MASK) return false; - if (IS_I9XX(dev)) { - if (obj_priv->gtt_offset & ~I915_FENCE_START_MASK) - return false; - } else { - if (obj_priv->gtt_offset & ~I830_FENCE_START_MASK) - return false; - } } return true; diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c index e64b8ea..2b5e54c 100644 --- a/drivers/gpu/drm/i915/i915_irq.c +++ b/drivers/gpu/drm/i915/i915_irq.c @@ -172,7 +172,7 @@ void intel_enable_asle (struct drm_device *dev) else { i915_enable_pipestat(dev_priv, 1, PIPE_LEGACY_BLC_EVENT_ENABLE); - if (IS_I965G(dev)) + if (INTEL_INFO(dev)->gen >= 4) i915_enable_pipestat(dev_priv, 0, PIPE_LEGACY_BLC_EVENT_ENABLE); } @@ -397,15 +397,18 @@ static void i915_error_work_func(struct work_struct *work) kobject_uevent_env(&dev->primary->kdev.kobj, KOBJ_CHANGE, error_event); if (atomic_read(&dev_priv->mm.wedged)) { - if (IS_I965G(dev)) { + switch (INTEL_INFO(dev)->gen) { + case 4: DRM_DEBUG_DRIVER("resetting chip\n"); kobject_uevent_env(&dev->primary->kdev.kobj, KOBJ_CHANGE, reset_event); if (!i965_reset(dev, GDRST_RENDER)) { atomic_set(&dev_priv->mm.wedged, 0); kobject_uevent_env(&dev->primary->kdev.kobj, KOBJ_CHANGE, reset_done_event); } - } else { + break; + default: DRM_DEBUG_DRIVER("reboot required\n"); + break; } } } @@ -501,7 +504,7 @@ i915_get_bbaddr(struct drm_device *dev, u32 *ring) if (IS_I830(dev) || IS_845G(dev)) cmd = MI_BATCH_BUFFER; - else if (IS_I965G(dev)) + else if (INTEL_INFO(dev)->gen >= 4) cmd = (MI_BATCH_BUFFER_START | (2 << 6) | MI_BATCH_NON_SECURE_I965); else @@ -580,7 +583,7 @@ static void i915_capture_error_state(struct drm_device *dev) error->pipeastat = I915_READ(PIPEASTAT); error->pipebstat = I915_READ(PIPEBSTAT); error->instpm = I915_READ(INSTPM); - if (!IS_I965G(dev)) { + if (INTEL_INFO(dev)->gen < 4) { error->ipeir = I915_READ(IPEIR); error->ipehr = I915_READ(IPEHR); error->instdone = I915_READ(INSTDONE); @@ -778,7 +781,7 @@ static void i915_report_and_clear_eir(struct drm_device *dev) } } - if (IS_I9XX(dev)) { + if (!IS_GEN2(dev)) { if (eir & I915_ERROR_PAGE_TABLE) { u32 pgtbl_err = I915_READ(PGTBL_ER); printk(KERN_ERR "page table error\n"); @@ -804,7 +807,7 @@ static void i915_report_and_clear_eir(struct drm_device *dev) printk(KERN_ERR "instruction error\n"); printk(KERN_ERR " INSTPM: 0x%08x\n", I915_READ(INSTPM)); - if (!IS_I965G(dev)) { + if (INTEL_INFO(dev)->gen < 4) { u32 ipeir = I915_READ(IPEIR); printk(KERN_ERR " IPEIR: 0x%08x\n", @@ -905,7 +908,7 @@ static void i915_pageflip_stall_check(struct drm_device *dev, int pipe) /* Potential stall - if we see that the flip has happened, assume a missed interrupt */ obj_priv = to_intel_bo(work->pending_flip_obj); - if(IS_I965G(dev)) { + if (INTEL_INFO(dev)->gen >= 4) { int dspsurf = intel_crtc->plane == 0 ? DSPASURF : DSPBSURF; stall_detected = I915_READ(dspsurf) == obj_priv->gtt_offset; } else { @@ -944,7 +947,7 @@ irqreturn_t i915_driver_irq_handler(DRM_IRQ_ARGS) iir = I915_READ(IIR); - if (IS_I965G(dev)) + if (INTEL_INFO(dev)->gen >= 4) vblank_status = PIPE_START_VBLANK_INTERRUPT_STATUS; else vblank_status = PIPE_VBLANK_INTERRUPT_STATUS; @@ -1209,7 +1212,7 @@ int i915_enable_vblank(struct drm_device *dev, int pipe) if (HAS_PCH_SPLIT(dev)) ironlake_enable_display_irq(dev_priv, (pipe == 0) ? DE_PIPEA_VBLANK: DE_PIPEB_VBLANK); - else if (IS_I965G(dev)) + else if (INTEL_INFO(dev)->gen >= 4) i915_enable_pipestat(dev_priv, pipe, PIPE_START_VBLANK_INTERRUPT_ENABLE); else @@ -1322,11 +1325,7 @@ void i915_hangcheck_elapsed(unsigned long data) drm_i915_private_t *dev_priv = dev->dev_private; uint32_t acthd, instdone, instdone1; - /* No reset support on this chip yet. */ - if (IS_GEN6(dev)) - return; - - if (!IS_I965G(dev)) { + if (INTEL_INFO(dev)->gen < 4) { acthd = I915_READ(ACTHD); instdone = I915_READ(INSTDONE); instdone1 = 0; diff --git a/drivers/gpu/drm/i915/i915_suspend.c b/drivers/gpu/drm/i915/i915_suspend.c index 967dcde..989c19d 100644 --- a/drivers/gpu/drm/i915/i915_suspend.c +++ b/drivers/gpu/drm/i915/i915_suspend.c @@ -256,7 +256,7 @@ static void i915_save_modeset_reg(struct drm_device *dev) dev_priv->saveFPA1 = I915_READ(FPA1); dev_priv->saveDPLL_A = I915_READ(DPLL_A); } - if (IS_I965G(dev) && !HAS_PCH_SPLIT(dev)) + if (INTEL_INFO(dev)->gen >= 4 && !HAS_PCH_SPLIT(dev)) dev_priv->saveDPLL_A_MD = I915_READ(DPLL_A_MD); dev_priv->saveHTOTAL_A = I915_READ(HTOTAL_A); dev_priv->saveHBLANK_A = I915_READ(HBLANK_A); @@ -294,7 +294,7 @@ static void i915_save_modeset_reg(struct drm_device *dev) dev_priv->saveDSPASIZE = I915_READ(DSPASIZE); dev_priv->saveDSPAPOS = I915_READ(DSPAPOS); dev_priv->saveDSPAADDR = I915_READ(DSPAADDR); - if (IS_I965G(dev)) { + if (INTEL_INFO(dev)->gen >= 4) { dev_priv->saveDSPASURF = I915_READ(DSPASURF); dev_priv->saveDSPATILEOFF = I915_READ(DSPATILEOFF); } @@ -313,7 +313,7 @@ static void i915_save_modeset_reg(struct drm_device *dev) dev_priv->saveFPB1 = I915_READ(FPB1); dev_priv->saveDPLL_B = I915_READ(DPLL_B); } - if (IS_I965G(dev) && !HAS_PCH_SPLIT(dev)) + if (INTEL_INFO(dev)->gen >= 4 && !HAS_PCH_SPLIT(dev)) dev_priv->saveDPLL_B_MD = I915_READ(DPLL_B_MD); dev_priv->saveHTOTAL_B = I915_READ(HTOTAL_B); dev_priv->saveHBLANK_B = I915_READ(HBLANK_B); @@ -351,7 +351,7 @@ static void i915_save_modeset_reg(struct drm_device *dev) dev_priv->saveDSPBSIZE = I915_READ(DSPBSIZE); dev_priv->saveDSPBPOS = I915_READ(DSPBPOS); dev_priv->saveDSPBADDR = I915_READ(DSPBADDR); - if (IS_I965GM(dev) || IS_GM45(dev)) { + if (INTEL_INFO(dev)->gen >= 4) { dev_priv->saveDSPBSURF = I915_READ(DSPBSURF); dev_priv->saveDSPBTILEOFF = I915_READ(DSPBTILEOFF); } @@ -404,7 +404,7 @@ static void i915_restore_modeset_reg(struct drm_device *dev) I915_WRITE(dpll_a_reg, dev_priv->saveDPLL_A); POSTING_READ(dpll_a_reg); udelay(150); - if (IS_I965G(dev) && !HAS_PCH_SPLIT(dev)) { + if (INTEL_INFO(dev)->gen >= 4 && !HAS_PCH_SPLIT(dev)) { I915_WRITE(DPLL_A_MD, dev_priv->saveDPLL_A_MD); POSTING_READ(DPLL_A_MD); } @@ -448,7 +448,7 @@ static void i915_restore_modeset_reg(struct drm_device *dev) I915_WRITE(PIPEASRC, dev_priv->savePIPEASRC); I915_WRITE(DSPAADDR, dev_priv->saveDSPAADDR); I915_WRITE(DSPASTRIDE, dev_priv->saveDSPASTRIDE); - if (IS_I965G(dev)) { + if (INTEL_INFO(dev)->gen >= 4) { I915_WRITE(DSPASURF, dev_priv->saveDSPASURF); I915_WRITE(DSPATILEOFF, dev_priv->saveDSPATILEOFF); } @@ -473,7 +473,7 @@ static void i915_restore_modeset_reg(struct drm_device *dev) I915_WRITE(dpll_b_reg, dev_priv->saveDPLL_B); POSTING_READ(dpll_b_reg); udelay(150); - if (IS_I965G(dev) && !HAS_PCH_SPLIT(dev)) { + if (INTEL_INFO(dev)->gen >= 4 && !HAS_PCH_SPLIT(dev)) { I915_WRITE(DPLL_B_MD, dev_priv->saveDPLL_B_MD); POSTING_READ(DPLL_B_MD); } @@ -517,7 +517,7 @@ static void i915_restore_modeset_reg(struct drm_device *dev) I915_WRITE(PIPEBSRC, dev_priv->savePIPEBSRC); I915_WRITE(DSPBADDR, dev_priv->saveDSPBADDR); I915_WRITE(DSPBSTRIDE, dev_priv->saveDSPBSTRIDE); - if (IS_I965G(dev)) { + if (INTEL_INFO(dev)->gen >= 4) { I915_WRITE(DSPBSURF, dev_priv->saveDSPBSURF); I915_WRITE(DSPBTILEOFF, dev_priv->saveDSPBTILEOFF); } @@ -550,7 +550,7 @@ void i915_save_display(struct drm_device *dev) dev_priv->saveCURBCNTR = I915_READ(CURBCNTR); dev_priv->saveCURBPOS = I915_READ(CURBPOS); dev_priv->saveCURBBASE = I915_READ(CURBBASE); - if (!IS_I9XX(dev)) + if (IS_GEN2(dev)) dev_priv->saveCURSIZE = I915_READ(CURSIZE); /* CRT state */ @@ -573,7 +573,7 @@ void i915_save_display(struct drm_device *dev) dev_priv->savePFIT_PGM_RATIOS = I915_READ(PFIT_PGM_RATIOS); dev_priv->saveBLC_PWM_CTL = I915_READ(BLC_PWM_CTL); dev_priv->saveBLC_HIST_CTL = I915_READ(BLC_HIST_CTL); - if (IS_I965G(dev)) + if (INTEL_INFO(dev)->gen >= 4) dev_priv->saveBLC_PWM_CTL2 = I915_READ(BLC_PWM_CTL2); if (IS_MOBILE(dev) && !IS_I830(dev)) dev_priv->saveLVDS = I915_READ(LVDS); @@ -664,7 +664,7 @@ void i915_restore_display(struct drm_device *dev) I915_WRITE(CURBPOS, dev_priv->saveCURBPOS); I915_WRITE(CURBCNTR, dev_priv->saveCURBCNTR); I915_WRITE(CURBBASE, dev_priv->saveCURBBASE); - if (!IS_I9XX(dev)) + if (IS_GEN2(dev)) I915_WRITE(CURSIZE, dev_priv->saveCURSIZE); /* CRT state */ @@ -674,7 +674,7 @@ void i915_restore_display(struct drm_device *dev) I915_WRITE(ADPA, dev_priv->saveADPA); /* LVDS state */ - if (IS_I965G(dev) && !HAS_PCH_SPLIT(dev)) + if (INTEL_INFO(dev)->gen >= 4 && !HAS_PCH_SPLIT(dev)) I915_WRITE(BLC_PWM_CTL2, dev_priv->saveBLC_PWM_CTL2); if (HAS_PCH_SPLIT(dev)) { diff --git a/drivers/gpu/drm/i915/intel_crt.c b/drivers/gpu/drm/i915/intel_crt.c index 6d33855..8e484c9 100644 --- a/drivers/gpu/drm/i915/intel_crt.c +++ b/drivers/gpu/drm/i915/intel_crt.c @@ -79,7 +79,7 @@ static int intel_crt_mode_valid(struct drm_connector *connector, if (mode->clock < 25000) return MODE_CLOCK_LOW; - if (!IS_I9XX(dev)) + if (IS_GEN2(dev)) max_clock = 350000; else max_clock = 400000; @@ -123,7 +123,7 @@ static void intel_crt_mode_set(struct drm_encoder *encoder, * Disable separate mode multiplier used when cloning SDVO to CRT * XXX this needs to be adjusted when we really are cloning */ - if (IS_I965G(dev) && !HAS_PCH_SPLIT(dev)) { + if (INTEL_INFO(dev)->gen >= 4 && !HAS_PCH_SPLIT(dev)) { dpll_md = I915_READ(dpll_md_reg); I915_WRITE(dpll_md_reg, dpll_md & ~DPLL_MD_UDI_MULTIPLIER_MASK); @@ -325,7 +325,7 @@ intel_crt_load_detect(struct drm_crtc *crtc, struct intel_encoder *intel_encoder /* Set the border color to purple. */ I915_WRITE(bclrpat_reg, 0x500050); - if (IS_I9XX(dev)) { + if (!IS_GEN2(dev)) { uint32_t pipeconf = I915_READ(pipeconf_reg); I915_WRITE(pipeconf_reg, pipeconf | PIPECONF_FORCE_BORDER); POSTING_READ(pipeconf_reg); @@ -411,7 +411,7 @@ intel_crt_detect(struct drm_connector *connector, bool force) int dpms_mode; enum drm_connector_status status; - if (IS_I9XX(dev) && !IS_I915G(dev) && !IS_I915GM(dev)) { + if (I915_HAS_HOTPLUG(dev)) { if (intel_crt_detect_hotplug(connector)) return connector_status_connected; else diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 1b5d878..c3f0400 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -708,16 +708,16 @@ static const intel_limit_t *intel_limit(struct drm_crtc *crtc) limit = intel_ironlake_limit(crtc); else if (IS_G4X(dev)) { limit = intel_g4x_limit(crtc); - } else if (IS_I9XX(dev) && !IS_PINEVIEW(dev)) { - if (intel_pipe_has_type(crtc, INTEL_OUTPUT_LVDS)) - limit = &intel_limits_i9xx_lvds; - else - limit = &intel_limits_i9xx_sdvo; } else if (IS_PINEVIEW(dev)) { if (intel_pipe_has_type(crtc, INTEL_OUTPUT_LVDS)) limit = &intel_limits_pineview_lvds; else limit = &intel_limits_pineview_sdvo; + } else if (!IS_GEN2(dev)) { + if (intel_pipe_has_type(crtc, INTEL_OUTPUT_LVDS)) + limit = &intel_limits_i9xx_lvds; + else + limit = &intel_limits_i9xx_sdvo; } else { if (intel_pipe_has_type(crtc, INTEL_OUTPUT_LVDS)) limit = &intel_limits_i8xx_lvds; @@ -1429,7 +1429,7 @@ intel_pin_and_fence_fb_obj(struct drm_device *dev, case I915_TILING_NONE: if (IS_BROADWATER(dev) || IS_CRESTLINE(dev)) alignment = 128 * 1024; - else if (IS_I965G(dev)) + else if (INTEL_INFO(dev)->gen >= 4) alignment = 4 * 1024; else alignment = 64 * 1024; @@ -1524,7 +1524,7 @@ intel_pipe_set_base_atomic(struct drm_crtc *crtc, struct drm_framebuffer *fb, DRM_ERROR("Unknown color depth\n"); return -EINVAL; } - if (IS_I965G(dev)) { + if (INTEL_INFO(dev)->gen >= 4) { if (obj_priv->tiling_mode != I915_TILING_NONE) dspcntr |= DISPPLANE_TILED; else @@ -1543,7 +1543,7 @@ intel_pipe_set_base_atomic(struct drm_crtc *crtc, struct drm_framebuffer *fb, DRM_DEBUG_KMS("Writing base %08lX %08lX %d %d %d\n", Start, Offset, x, y, fb->pitch); I915_WRITE(DSPSTRIDE(plane), fb->pitch); - if (IS_I965G(dev)) { + if (INTEL_INFO(dev)->gen >= 4) { I915_WRITE(DSPSURF(plane), Start); I915_WRITE(DSPTILEOFF(plane), (y << 16) | x); I915_WRITE(DSPADDR(plane), Offset); @@ -2388,7 +2388,7 @@ static void i9xx_crtc_disable(struct drm_crtc *crtc) intel_flush_display_plane(dev, plane); /* Wait for vblank for the disable to take effect */ - if (!IS_I9XX(dev)) + if (IS_GEN2(dev)) intel_wait_for_vblank_off(dev, pipe); } @@ -3181,11 +3181,11 @@ static void i965_update_wm(struct drm_device *dev, int planea_clock, DRM_DEBUG_KMS("self-refresh watermark: display plane %d " "cursor %d\n", srwm, cursor_sr); - if (IS_I965GM(dev)) + if (IS_CRESTLINE(dev)) I915_WRITE(FW_BLC_SELF, FW_BLC_SELF_EN); } else { /* Turn off self refresh if both pipes are enabled */ - if (IS_I965GM(dev)) + if (IS_CRESTLINE(dev)) I915_WRITE(FW_BLC_SELF, I915_READ(FW_BLC_SELF) & ~FW_BLC_SELF_EN); } @@ -3215,9 +3215,9 @@ static void i9xx_update_wm(struct drm_device *dev, int planea_clock, int sr_clock, sr_entries = 0; /* Create copies of the base settings for each pipe */ - if (IS_I965GM(dev) || IS_I945GM(dev)) + if (IS_CRESTLINE(dev) || IS_I945GM(dev)) planea_params = planeb_params = i945_wm_info; - else if (IS_I9XX(dev)) + else if (!IS_GEN2(dev)) planea_params = planeb_params = i915_wm_info; else planea_params = planeb_params = i855_wm_info; @@ -3576,7 +3576,7 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc, refclk = dev_priv->lvds_ssc_freq * 1000; DRM_DEBUG_KMS("using SSC reference clock of %d MHz\n", refclk / 1000); - } else if (IS_I9XX(dev)) { + } else if (!IS_GEN2(dev)) { refclk = 96000; if (HAS_PCH_SPLIT(dev)) refclk = 120000; /* 120Mhz refclk */ @@ -3775,7 +3775,7 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc, if (!HAS_PCH_SPLIT(dev)) dpll = DPLL_VGA_MODE_DIS; - if (IS_I9XX(dev)) { + if (!IS_GEN2(dev)) { if (is_lvds) dpll |= DPLLB_MODE_LVDS; else @@ -3818,7 +3818,7 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc, dpll |= DPLLB_LVDS_P2_CLOCK_DIV_14; break; } - if (IS_I965G(dev) && !HAS_PCH_SPLIT(dev)) + if (INTEL_INFO(dev)->gen >= 4 && !HAS_PCH_SPLIT(dev)) dpll |= (6 << PLL_LOAD_PULSE_PHASE_SHIFT); } else { if (is_lvds) { @@ -3859,7 +3859,7 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc, dspcntr |= DISPPLANE_SEL_PIPE_B; } - if (pipe == 0 && !IS_I965G(dev)) { + if (pipe == 0 && INTEL_INFO(dev)->gen < 4) { /* Enable pixel doubling when the dot clock is > 90% of the (display) * core speed. * @@ -3947,7 +3947,7 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc, * panels behave in the two modes. */ /* set the dithering flag on non-PCH LVDS as needed */ - if (IS_I965G(dev) && !HAS_PCH_SPLIT(dev)) { + if (INTEL_INFO(dev)->gen >= 4 && !HAS_PCH_SPLIT(dev)) { if (dev_priv->lvds_dither) temp |= LVDS_ENABLE_DITHER; else @@ -3991,7 +3991,7 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc, POSTING_READ(dpll_reg); udelay(150); - if (IS_I965G(dev) && !HAS_PCH_SPLIT(dev)) { + if (INTEL_INFO(dev)->gen >= 4 && !HAS_PCH_SPLIT(dev)) { temp = 0; if (is_sdvo) { temp = intel_mode_get_pixel_multiplier(adjusted_mode); @@ -4334,7 +4334,7 @@ static int intel_crtc_cursor_set(struct drm_crtc *crtc, addr = obj_priv->phys_obj->handle->busaddr; } - if (!IS_I9XX(dev)) + if (IS_GEN2(dev)) I915_WRITE(CURSIZE, (height << 12) | width); finish: @@ -4569,7 +4569,7 @@ static int intel_crtc_clock_get(struct drm_device *dev, struct drm_crtc *crtc) clock.m2 = (fp & FP_M2_DIV_MASK) >> FP_M2_DIV_SHIFT; } - if (IS_I9XX(dev)) { + if (!IS_GEN2(dev)) { if (IS_PINEVIEW(dev)) clock.p1 = ffs((dpll & DPLL_FPA01_P1_POST_DIV_MASK_PINEVIEW) >> DPLL_FPA01_P1_POST_DIV_SHIFT_PINEVIEW); @@ -5768,20 +5768,20 @@ void intel_init_clock_gating(struct drm_device *dev) if (IS_GM45(dev)) dspclk_gate |= DSSUNIT_CLOCK_GATE_DISABLE; I915_WRITE(DSPCLK_GATE_D, dspclk_gate); - } else if (IS_I965GM(dev)) { + } else if (IS_CRESTLINE(dev)) { I915_WRITE(RENCLK_GATE_D1, I965_RCC_CLOCK_GATE_DISABLE); I915_WRITE(RENCLK_GATE_D2, 0); I915_WRITE(DSPCLK_GATE_D, 0); I915_WRITE(RAMCLK_GATE_D, 0); I915_WRITE16(DEUC, 0); - } else if (IS_I965G(dev)) { + } else if (IS_BROADWATER(dev)) { I915_WRITE(RENCLK_GATE_D1, I965_RCZ_CLOCK_GATE_DISABLE | I965_RCC_CLOCK_GATE_DISABLE | I965_RCPB_CLOCK_GATE_DISABLE | I965_ISC_CLOCK_GATE_DISABLE | I965_FBC_CLOCK_GATE_DISABLE); I915_WRITE(RENCLK_GATE_D2, 0); - } else if (IS_I9XX(dev)) { + } else if (IS_GEN3(dev)) { u32 dstate = I915_READ(D_STATE); dstate |= DSTATE_PLL_D3_OFF | DSTATE_GFX_CLOCK_GATING | @@ -5863,7 +5863,7 @@ static void intel_init_display(struct drm_device *dev) dev_priv->display.fbc_enabled = g4x_fbc_enabled; dev_priv->display.enable_fbc = g4x_enable_fbc; dev_priv->display.disable_fbc = g4x_disable_fbc; - } else if (IS_I965GM(dev)) { + } else if (IS_CRESTLINE(dev)) { dev_priv->display.fbc_enabled = i8xx_fbc_enabled; dev_priv->display.enable_fbc = i8xx_enable_fbc; dev_priv->display.disable_fbc = i8xx_disable_fbc; @@ -5923,9 +5923,9 @@ static void intel_init_display(struct drm_device *dev) dev_priv->display.update_wm = pineview_update_wm; } else if (IS_G4X(dev)) dev_priv->display.update_wm = g4x_update_wm; - else if (IS_I965G(dev)) + else if (IS_GEN4(dev)) dev_priv->display.update_wm = i965_update_wm; - else if (IS_I9XX(dev)) { + else if (IS_GEN3(dev)) { dev_priv->display.update_wm = i9xx_update_wm; dev_priv->display.get_fifo_size = i9xx_get_fifo_size; } else if (IS_I85X(dev)) { @@ -6039,24 +6039,24 @@ void intel_modeset_init(struct drm_device *dev) intel_init_display(dev); - if (IS_I965G(dev)) { - dev->mode_config.max_width = 8192; - dev->mode_config.max_height = 8192; - } else if (IS_I9XX(dev)) { + if (IS_GEN2(dev)) { + dev->mode_config.max_width = 2048; + dev->mode_config.max_height = 2048; + } else if (IS_GEN3(dev)) { dev->mode_config.max_width = 4096; dev->mode_config.max_height = 4096; } else { - dev->mode_config.max_width = 2048; - dev->mode_config.max_height = 2048; + dev->mode_config.max_width = 8192; + dev->mode_config.max_height = 8192; } /* set memory base */ - if (IS_I9XX(dev)) - dev->mode_config.fb_base = pci_resource_start(dev->pdev, 2); - else + if (IS_GEN2(dev)) dev->mode_config.fb_base = pci_resource_start(dev->pdev, 0); + else + dev->mode_config.fb_base = pci_resource_start(dev->pdev, 2); - if (IS_MOBILE(dev) || IS_I9XX(dev)) + if (IS_MOBILE(dev) || !IS_GEN2(dev)) dev_priv->num_pipe = 2; else dev_priv->num_pipe = 1; diff --git a/drivers/gpu/drm/i915/intel_fb.c b/drivers/gpu/drm/i915/intel_fb.c index 8a23bf7..7af4acc 100644 --- a/drivers/gpu/drm/i915/intel_fb.c +++ b/drivers/gpu/drm/i915/intel_fb.c @@ -68,7 +68,7 @@ static int intelfb_create(struct intel_fbdev *ifbdev, struct drm_gem_object *fbo = NULL; struct drm_i915_gem_object *obj_priv; struct device *device = &dev->pdev->dev; - int size, ret, mmio_bar = IS_I9XX(dev) ? 0 : 1; + int size, ret, mmio_bar = IS_GEN2(dev) ? 1 : 0; /* we don't do packed 24bpp */ if (sizes->surface_bpp == 24) @@ -129,7 +129,7 @@ static int intelfb_create(struct intel_fbdev *ifbdev, goto out_unpin; } info->apertures->ranges[0].base = dev->mode_config.fb_base; - if (IS_I9XX(dev)) + if (!IS_GEN2(dev)) info->apertures->ranges[0].size = pci_resource_len(dev->pdev, 2); else info->apertures->ranges[0].size = pci_resource_len(dev->pdev, 0); diff --git a/drivers/gpu/drm/i915/intel_lvds.c b/drivers/gpu/drm/i915/intel_lvds.c index 5666e89..02c5aed 100644 --- a/drivers/gpu/drm/i915/intel_lvds.c +++ b/drivers/gpu/drm/i915/intel_lvds.c @@ -198,7 +198,7 @@ static bool intel_lvds_mode_fixup(struct drm_encoder *encoder, u32 pfit_control = 0, pfit_pgm_ratios = 0, border = 0; /* Should never happen!! */ - if (!IS_I965G(dev) && intel_crtc->pipe == 0) { + if (INTEL_INFO(dev)->gen < 4 && intel_crtc->pipe == 0) { DRM_ERROR("Can't support LVDS on pipe A\n"); return false; } @@ -227,7 +227,7 @@ static bool intel_lvds_mode_fixup(struct drm_encoder *encoder, } /* Make sure pre-965s set dither correctly */ - if (!IS_I965G(dev)) { + if (INTEL_INFO(dev)->gen < 4) { if (dev_priv->panel_wants_dither || dev_priv->lvds_dither) pfit_control |= PANEL_8TO6_DITHER_ENABLE; } @@ -238,7 +238,7 @@ static bool intel_lvds_mode_fixup(struct drm_encoder *encoder, goto out; /* 965+ wants fuzzy fitting */ - if (IS_I965G(dev)) + if (INTEL_INFO(dev)->gen >= 4) pfit_control |= ((intel_crtc->pipe << PFIT_PIPE_SHIFT) | PFIT_FILTER_FUZZY); @@ -264,7 +264,7 @@ static bool intel_lvds_mode_fixup(struct drm_encoder *encoder, case DRM_MODE_SCALE_ASPECT: /* Scale but preserve the aspect ratio */ - if (IS_I965G(dev)) { + if (INTEL_INFO(dev)->gen >= 4) { u32 scaled_width = adjusted_mode->hdisplay * mode->vdisplay; u32 scaled_height = mode->hdisplay * adjusted_mode->vdisplay; @@ -323,7 +323,7 @@ static bool intel_lvds_mode_fixup(struct drm_encoder *encoder, * Fortunately this is all done for us in hw. */ pfit_control |= PFIT_ENABLE; - if (IS_I965G(dev)) + if (INTEL_INFO(dev)->gen >= 4) pfit_control |= PFIT_SCALING_AUTO; else pfit_control |= (VERT_AUTO_SCALE | HORIZ_AUTO_SCALE | diff --git a/drivers/gpu/drm/i915/intel_overlay.c b/drivers/gpu/drm/i915/intel_overlay.c index c4699c9..375316a 100644 --- a/drivers/gpu/drm/i915/intel_overlay.c +++ b/drivers/gpu/drm/i915/intel_overlay.c @@ -552,15 +552,15 @@ static int uv_vsubsampling(u32 format) static u32 calc_swidthsw(struct drm_device *dev, u32 offset, u32 width) { u32 mask, shift, ret; - if (IS_I9XX(dev)) { - mask = 0x3f; - shift = 6; - } else { + if (IS_GEN2(dev)) { mask = 0x1f; shift = 5; + } else { + mask = 0x3f; + shift = 6; } ret = ((offset + width + mask) >> shift) - (offset >> shift); - if (IS_I9XX(dev)) + if (!IS_GEN2(dev)) ret <<= 1; ret -=1; return ret << 2; @@ -768,7 +768,7 @@ static int intel_overlay_do_put_image(struct intel_overlay *overlay, goto out_unpin; } regs->OCONFIG = OCONF_CC_OUT_8BIT; - if (IS_I965GM(overlay->dev)) + if (IS_GEN4(overlay->dev)) regs->OCONFIG |= OCONF_CSC_MODE_BT709; regs->OCONFIG |= overlay->crtc->pipe == 0 ? OCONF_PIPE_A : OCONF_PIPE_B; @@ -880,7 +880,7 @@ static int check_overlay_possible_on_crtc(struct intel_overlay *overlay, return -EINVAL; /* can't use the overlay with double wide pipe */ - if (!IS_I965G(overlay->dev) && + if (INTEL_INFO(overlay->dev)->gen < 4 && (I915_READ(PIPECONF(crtc->pipe)) & (PIPECONF_DOUBLE_WIDE | PIPECONF_ENABLE)) != PIPECONF_ENABLE) return -EINVAL; @@ -897,14 +897,15 @@ static void update_pfit_vscale_ratio(struct intel_overlay *overlay) /* XXX: This is not the same logic as in the xorg driver, but more in * line with the intel documentation for the i965 */ - if (!IS_I965G(dev)) { + if (INTEL_INFO(dev)->gen >= 4) { + /* on i965 use the PGM reg to read out the autoscaler values */ + ratio = I915_READ(PFIT_PGM_RATIOS) >> PFIT_VERT_SCALE_SHIFT_965; + } else { if (pfit_control & VERT_AUTO_SCALE) ratio = I915_READ(PFIT_AUTO_RATIOS); else ratio = I915_READ(PFIT_PGM_RATIOS); ratio >>= PFIT_VERT_SCALE_SHIFT; - } else { /* on i965 use the PGM reg to read out the autoscaler values */ - ratio = I915_READ(PFIT_PGM_RATIOS) >> PFIT_VERT_SCALE_SHIFT_965; } overlay->pfit_vscale_ratio = ratio; @@ -1007,7 +1008,7 @@ static int check_overlay_src(struct drm_device *dev, if (rec->stride_Y & stride_mask || rec->stride_UV & stride_mask) return -EINVAL; - if (IS_I965G(dev) && rec->stride_Y < 512) + if (IS_GEN4(dev) && rec->stride_Y < 512) return -EINVAL; tmp = (rec->flags & I915_OVERLAY_TYPE_MASK) == I915_OVERLAY_YUV_PLANAR ? @@ -1068,7 +1069,7 @@ static int intel_panel_fitter_pipe(struct drm_device *dev) return -1; /* 965 can place panel fitter on either pipe */ - if (IS_I965G(dev)) + if (IS_GEN4(dev)) return (pfit_control >> 29) & 0x3; /* older chips can only use pipe 1 */ @@ -1302,7 +1303,7 @@ int intel_overlay_attrs(struct drm_device *dev, void *data, attrs->contrast = overlay->contrast; attrs->saturation = overlay->saturation; - if (IS_I9XX(dev)) { + if (!IS_GEN2(dev)) { attrs->gamma0 = I915_READ(OGAMC0); attrs->gamma1 = I915_READ(OGAMC1); attrs->gamma2 = I915_READ(OGAMC2); @@ -1334,7 +1335,7 @@ int intel_overlay_attrs(struct drm_device *dev, void *data, intel_overlay_unmap_regs(overlay, regs); if (attrs->flags & I915_OVERLAY_UPDATE_GAMMA) { - if (!IS_I9XX(dev)) + if (IS_GEN2(dev)) goto out_unlock; if (overlay->active) { diff --git a/drivers/gpu/drm/i915/intel_panel.c b/drivers/gpu/drm/i915/intel_panel.c index 30abe7a..92ff8f3 100644 --- a/drivers/gpu/drm/i915/intel_panel.c +++ b/drivers/gpu/drm/i915/intel_panel.c @@ -116,7 +116,7 @@ static int is_backlight_combination_mode(struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; - if (IS_I965G(dev)) + if (INTEL_INFO(dev)->gen >= 4) return I915_READ(BLC_PWM_CTL2) & BLM_COMBINATION_MODE; if (IS_GEN2(dev)) @@ -138,7 +138,7 @@ u32 intel_panel_get_max_backlight(struct drm_device *dev) max >>= 17; } else { max >>= 16; - if (!IS_I965G(dev)) + if (INTEL_INFO(dev)->gen < 4) max &= ~1; } diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.c b/drivers/gpu/drm/i915/intel_ringbuffer.c index 11bcfc8..670f94a 100644 --- a/drivers/gpu/drm/i915/intel_ringbuffer.c +++ b/drivers/gpu/drm/i915/intel_ringbuffer.c @@ -97,7 +97,7 @@ render_ring_flush(struct drm_device *dev, if ((invalidate_domains|flush_domains) & I915_GEM_DOMAIN_RENDER) cmd &= ~MI_NO_WRITE_FLUSH; - if (!IS_I965G(dev)) { + if (INTEL_INFO(dev)->gen < 4) { /* * On the 965, the sampler cache always gets flushed * and this bit is reserved. @@ -138,7 +138,7 @@ static unsigned int render_ring_get_active_head(struct drm_device *dev, struct intel_ring_buffer *ring) { drm_i915_private_t *dev_priv = dev->dev_private; - u32 acthd_reg = IS_I965G(dev) ? ACTHD_I965 : ACTHD; + u32 acthd_reg = INTEL_INFO(dev)->gen ? ACTHD_I965 : ACTHD; return I915_READ(acthd_reg); } @@ -224,7 +224,7 @@ static int init_render_ring(struct drm_device *dev, int ret = init_ring_common(dev, ring); int mode; - if (IS_I9XX(dev) && !IS_GEN3(dev)) { + if (INTEL_INFO(dev)->gen > 3) { mode = VS_TIMER_DISPATCH << 16 | VS_TIMER_DISPATCH; if (IS_GEN6(dev)) mode |= MI_FLUSH_ENABLE << 16 | MI_FLUSH_ENABLE; @@ -528,7 +528,7 @@ render_ring_dispatch_gem_execbuffer(struct drm_device *dev, intel_ring_emit(dev, ring, 0); } else { intel_ring_begin(dev, ring, 4); - if (IS_I965G(dev)) { + if (INTEL_INFO(dev)->gen >= 4) { intel_ring_emit(dev, ring, MI_BATCH_BUFFER_START | (2 << 6) | MI_BATCH_NON_SECURE_I965); diff --git a/drivers/gpu/drm/i915/intel_sdvo.c b/drivers/gpu/drm/i915/intel_sdvo.c index ba058e6..7cd2d95 100644 --- a/drivers/gpu/drm/i915/intel_sdvo.c +++ b/drivers/gpu/drm/i915/intel_sdvo.c @@ -1162,7 +1162,7 @@ static void intel_sdvo_mode_set(struct drm_encoder *encoder, return; /* Set the SDVO control regs. */ - if (IS_I965G(dev)) { + if (INTEL_INFO(dev)->gen >= 4) { sdvox = SDVO_BORDER_ENABLE; if (adjusted_mode->flags & DRM_MODE_FLAG_PVSYNC) sdvox |= SDVO_VSYNC_ACTIVE_HIGH; @@ -1185,7 +1185,7 @@ static void intel_sdvo_mode_set(struct drm_encoder *encoder, if (intel_sdvo->is_hdmi) sdvox |= SDVO_AUDIO_ENABLE; - if (IS_I965G(dev)) { + if (INTEL_INFO(dev)->gen >= 4) { /* done in crtc_mode_set as the dpll_md reg must be written early */ } else if (IS_I945G(dev) || IS_I945GM(dev) || IS_G33(dev)) { /* done in crtc_mode_set as it lives inside the dpll register */ diff --git a/drivers/gpu/drm/i915/intel_tv.c b/drivers/gpu/drm/i915/intel_tv.c index e03783f..49ab11c 100644 --- a/drivers/gpu/drm/i915/intel_tv.c +++ b/drivers/gpu/drm/i915/intel_tv.c @@ -1139,7 +1139,7 @@ intel_tv_mode_set(struct drm_encoder *encoder, struct drm_display_mode *mode, color_conversion->av); } - if (IS_I965G(dev)) + if (INTEL_INFO(dev)->gen >= 4) I915_WRITE(TV_CLR_KNOBS, 0x00404000); else I915_WRITE(TV_CLR_KNOBS, 0x00606000); @@ -1165,7 +1165,7 @@ intel_tv_mode_set(struct drm_encoder *encoder, struct drm_display_mode *mode, I915_WRITE(dspbase_reg, I915_READ(dspbase_reg)); /* Wait for vblank for the disable to take effect */ - if (!IS_I9XX(dev)) + if (IS_GEN2(dev)) intel_wait_for_vblank(dev, intel_crtc->pipe); I915_WRITE(pipeconf_reg, pipeconf & ~PIPECONF_ENABLE); -- cgit v1.1 From f49f0586191fe16140410db0a46d43bdc690d6af Mon Sep 17 00:00:00 2001 From: Kenneth Graunke Date: Sat, 11 Sep 2010 01:19:14 -0700 Subject: drm/i915: Actually set the reset bit in i965_reset. Previously, it was only being set if passed GDRST_FULL - but the only caller passed GDRST_RENDER. So the hardware never actually reset. The comments also did not match the code. Instead, just set the reset bit regardless of what flags were passed. The GPU now resets correctly on my GM45. Signed-off-by: Kenneth Graunke Signed-off-by: Chris Wilson --- drivers/gpu/drm/i915/i915_drv.c | 31 +++++++++++++++---------------- 1 file changed, 15 insertions(+), 16 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_drv.c b/drivers/gpu/drm/i915/i915_drv.c index 87c6b5f..7209997 100644 --- a/drivers/gpu/drm/i915/i915_drv.c +++ b/drivers/gpu/drm/i915/i915_drv.c @@ -32,6 +32,7 @@ #include "drm.h" #include "i915_drm.h" #include "i915_drv.h" +#include "intel_drv.h" #include #include "drm_crtc_helper.h" @@ -326,6 +327,13 @@ int i915_resume(struct drm_device *dev) return i915_drm_thaw(dev); } +static int i965_reset_complete(struct drm_device *dev) +{ + u8 gdrst; + pci_read_config_byte(dev->pdev, GDRST, &gdrst); + return gdrst & 0x1; +} + /** * i965_reset - reset chip after a hang * @dev: drm device to reset @@ -345,7 +353,6 @@ int i915_resume(struct drm_device *dev) int i965_reset(struct drm_device *dev, u8 flags) { drm_i915_private_t *dev_priv = dev->dev_private; - unsigned long timeout; u8 gdrst; /* * We really should only reset the display subsystem if we actually @@ -364,23 +371,15 @@ int i965_reset(struct drm_device *dev, u8 flags) i915_save_display(dev); /* - * Set the domains we want to reset, then the reset bit (bit 0). - * Clear the reset bit after a while and wait for hardware status - * bit (bit 1) to be set + * Set the domains we want to reset (GRDOM/bits 2 and 3) as + * well as the reset bit (GR/bit 0). Setting the GR bit + * triggers the reset; when done, the hardware will clear it. */ pci_read_config_byte(dev->pdev, GDRST, &gdrst); - pci_write_config_byte(dev->pdev, GDRST, gdrst | flags | ((flags == GDRST_FULL) ? 0x1 : 0x0)); - udelay(50); - pci_write_config_byte(dev->pdev, GDRST, gdrst & 0xfe); - - /* ...we don't want to loop forever though, 500ms should be plenty */ - timeout = jiffies + msecs_to_jiffies(500); - do { - udelay(100); - pci_read_config_byte(dev->pdev, GDRST, &gdrst); - } while ((gdrst & 0x1) && time_after(timeout, jiffies)); - - if (gdrst & 0x1) { + pci_write_config_byte(dev->pdev, GDRST, gdrst | flags | 0x1); + + /* Wait for the hardware to reset (but no more than 500 ms) */ + if (wait_for(i965_reset_complete(dev), 500)) { WARN(true, "i915: Failed to reset chip\n"); mutex_unlock(&dev->struct_mutex); return -EIO; -- cgit v1.1 From eeccdcac07c1e21d25e7d3cf70030059a3017f0c Mon Sep 17 00:00:00 2001 From: Kenneth Graunke Date: Sat, 11 Sep 2010 01:24:50 -0700 Subject: drm/i915: Rename graphics reset registers. The graphics domains are listed as GRDOM in the documentation, and the GDRST PCI config register (0xc0) is only valid on I965 and GM45. Newer chips (like Sandy Bridge) have a different GDRST. Signed-off-by: Kenneth Graunke Signed-off-by: Chris Wilson --- drivers/gpu/drm/i915/i915_drv.c | 6 +++--- drivers/gpu/drm/i915/i915_irq.c | 2 +- drivers/gpu/drm/i915/i915_reg.h | 10 ++++++---- 3 files changed, 10 insertions(+), 8 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_drv.c b/drivers/gpu/drm/i915/i915_drv.c index 7209997..45027d5 100644 --- a/drivers/gpu/drm/i915/i915_drv.c +++ b/drivers/gpu/drm/i915/i915_drv.c @@ -330,7 +330,7 @@ int i915_resume(struct drm_device *dev) static int i965_reset_complete(struct drm_device *dev) { u8 gdrst; - pci_read_config_byte(dev->pdev, GDRST, &gdrst); + pci_read_config_byte(dev->pdev, I965_GDRST, &gdrst); return gdrst & 0x1; } @@ -375,8 +375,8 @@ int i965_reset(struct drm_device *dev, u8 flags) * well as the reset bit (GR/bit 0). Setting the GR bit * triggers the reset; when done, the hardware will clear it. */ - pci_read_config_byte(dev->pdev, GDRST, &gdrst); - pci_write_config_byte(dev->pdev, GDRST, gdrst | flags | 0x1); + pci_read_config_byte(dev->pdev, I965_GDRST, &gdrst); + pci_write_config_byte(dev->pdev, I965_GDRST, gdrst | flags | 0x1); /* Wait for the hardware to reset (but no more than 500 ms) */ if (wait_for(i965_reset_complete(dev), 500)) { diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c index 2b5e54c..b1dc943 100644 --- a/drivers/gpu/drm/i915/i915_irq.c +++ b/drivers/gpu/drm/i915/i915_irq.c @@ -401,7 +401,7 @@ static void i915_error_work_func(struct work_struct *work) case 4: DRM_DEBUG_DRIVER("resetting chip\n"); kobject_uevent_env(&dev->primary->kdev.kobj, KOBJ_CHANGE, reset_event); - if (!i965_reset(dev, GDRST_RENDER)) { + if (!i965_reset(dev, GRDOM_RENDER)) { atomic_set(&dev_priv->mm.wedged, 0); kobject_uevent_env(&dev->primary->kdev.kobj, KOBJ_CHANGE, reset_done_event); } diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index 18e3749..565a7a3 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -108,10 +108,12 @@ #define I915_GC_RENDER_CLOCK_200_MHZ (1 << 0) #define I915_GC_RENDER_CLOCK_333_MHZ (4 << 0) #define LBB 0xf4 -#define GDRST 0xc0 -#define GDRST_FULL (0<<2) -#define GDRST_RENDER (1<<2) -#define GDRST_MEDIA (3<<2) + +/* Graphics reset regs */ +#define I965_GDRST 0xc0 +#define GRDOM_FULL (0<<2) +#define GRDOM_RENDER (1<<2) +#define GRDOM_MEDIA (3<<2) /* VGA stuff */ -- cgit v1.1 From 0573ed4a947d7a563db197511611d8a9039feb41 Mon Sep 17 00:00:00 2001 From: Kenneth Graunke Date: Sat, 11 Sep 2010 03:17:19 -0700 Subject: drm/i915: Add support for GPU soft reset on Ironlake. Ironlake's graphics reset register has to be accessed via the MCHBAR, rather than via PCI config space, which requires some refactoring. Signed-off-by: Kenneth Graunke Signed-off-by: Chris Wilson --- drivers/gpu/drm/i915/i915_drv.c | 30 ++++++++++++++++++++++++------ drivers/gpu/drm/i915/i915_irq.c | 1 + drivers/gpu/drm/i915/i915_reg.h | 3 ++- 3 files changed, 27 insertions(+), 7 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_drv.c b/drivers/gpu/drm/i915/i915_drv.c index 45027d5..e88aabd 100644 --- a/drivers/gpu/drm/i915/i915_drv.c +++ b/drivers/gpu/drm/i915/i915_drv.c @@ -334,6 +334,24 @@ static int i965_reset_complete(struct drm_device *dev) return gdrst & 0x1; } +static int i965_do_reset(struct drm_device *dev, u8 flags) +{ + u8 gdrst; + + pci_read_config_byte(dev->pdev, I965_GDRST, &gdrst); + pci_write_config_byte(dev->pdev, I965_GDRST, gdrst | flags | 0x1); + + return wait_for(i965_reset_complete(dev), 500); +} + +static int ironlake_do_reset(struct drm_device *dev, u8 flags) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + u32 gdrst = I915_READ(MCHBAR_MIRROR_BASE + ILK_GDSR); + I915_WRITE(MCHBAR_MIRROR_BASE + ILK_GDSR, gdrst | flags | 0x1); + return wait_for(I915_READ(MCHBAR_MIRROR_BASE + ILK_GDSR) & 0x1, 500); +} + /** * i965_reset - reset chip after a hang * @dev: drm device to reset @@ -353,12 +371,12 @@ static int i965_reset_complete(struct drm_device *dev) int i965_reset(struct drm_device *dev, u8 flags) { drm_i915_private_t *dev_priv = dev->dev_private; - u8 gdrst; /* * We really should only reset the display subsystem if we actually * need to */ bool need_display = true; + int ret; mutex_lock(&dev->struct_mutex); @@ -375,11 +393,11 @@ int i965_reset(struct drm_device *dev, u8 flags) * well as the reset bit (GR/bit 0). Setting the GR bit * triggers the reset; when done, the hardware will clear it. */ - pci_read_config_byte(dev->pdev, I965_GDRST, &gdrst); - pci_write_config_byte(dev->pdev, I965_GDRST, gdrst | flags | 0x1); - - /* Wait for the hardware to reset (but no more than 500 ms) */ - if (wait_for(i965_reset_complete(dev), 500)) { + if (IS_IRONLAKE(dev)) + ret = ironlake_do_reset(dev, flags); + else + ret = i965_do_reset(dev, flags); + if (ret) { WARN(true, "i915: Failed to reset chip\n"); mutex_unlock(&dev->struct_mutex); return -EIO; diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c index b1dc943..a5197e1 100644 --- a/drivers/gpu/drm/i915/i915_irq.c +++ b/drivers/gpu/drm/i915/i915_irq.c @@ -398,6 +398,7 @@ static void i915_error_work_func(struct work_struct *work) if (atomic_read(&dev_priv->mm.wedged)) { switch (INTEL_INFO(dev)->gen) { + case 5: case 4: DRM_DEBUG_DRIVER("resetting chip\n"); kobject_uevent_env(&dev->primary->kdev.kobj, KOBJ_CHANGE, reset_event); diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index 565a7a3..b46e580 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -110,7 +110,8 @@ #define LBB 0xf4 /* Graphics reset regs */ -#define I965_GDRST 0xc0 +#define I965_GDRST 0xc0 /* PCI config register */ +#define ILK_GDSR 0x2ca4 /* MCHBAR offset */ #define GRDOM_FULL (0<<2) #define GRDOM_RENDER (1<<2) #define GRDOM_MEDIA (3<<2) -- cgit v1.1 From 9fd981413e005827e7363a37fd0b61f9d0928034 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Sat, 18 Sep 2010 08:08:06 +0100 Subject: drm/i915: After a reset perform a forced modeset On more recent chipsets, restoring the display is not as simple as writing a few registers, so force a full modeset of the current configuration in order to retrain the display link. Signed-off-by: Chris Wilson --- drivers/gpu/drm/i915/i915_drv.c | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_drv.c b/drivers/gpu/drm/i915/i915_drv.c index e88aabd..e58e917 100644 --- a/drivers/gpu/drm/i915/i915_drv.c +++ b/drivers/gpu/drm/i915/i915_drv.c @@ -385,9 +385,6 @@ int i965_reset(struct drm_device *dev, u8 flags) */ i915_gem_retire_requests(dev); - if (need_display) - i915_save_display(dev); - /* * Set the domains we want to reset (GRDOM/bits 2 and 3) as * well as the reset bit (GR/bit 0). Setting the GR bit @@ -428,13 +425,19 @@ int i965_reset(struct drm_device *dev, u8 flags) mutex_lock(&dev->struct_mutex); } + mutex_unlock(&dev->struct_mutex); + /* - * Display needs restore too... + * Perform a full modeset as on later generations, e.g. Ironlake, we may + * need to retrain the display link and cannot just restore the register + * values. */ - if (need_display) - i915_restore_display(dev); + if (need_display) { + mutex_lock(&dev->mode_config.mutex); + drm_helper_resume_force_mode(dev); + mutex_unlock(&dev->mode_config.mutex); + } - mutex_unlock(&dev->struct_mutex); return 0; } -- cgit v1.1 From 82690bba375586ab93d74265710c2fd5788c8178 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Sat, 18 Sep 2010 01:37:30 +0100 Subject: drm/i915/debug: Dump BSD ring buffers to debugfs Signed-off-by: Chris Wilson --- drivers/gpu/drm/i915/i915_debugfs.c | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_debugfs.c b/drivers/gpu/drm/i915/i915_debugfs.c index 361a825..ac48115 100644 --- a/drivers/gpu/drm/i915/i915_debugfs.c +++ b/drivers/gpu/drm/i915/i915_debugfs.c @@ -40,9 +40,10 @@ #if defined(CONFIG_DEBUG_FS) -#define ACTIVE_LIST 1 -#define FLUSHING_LIST 2 -#define INACTIVE_LIST 3 +#define RENDER_LIST 1 +#define BSD_LIST 2 +#define FLUSHING_LIST 3 +#define INACTIVE_LIST 4 static const char *yesno(int v) { @@ -137,10 +138,14 @@ static int i915_gem_object_list_info(struct seq_file *m, void *data) return ret; switch (list) { - case ACTIVE_LIST: - seq_printf(m, "Active:\n"); + case RENDER_LIST: + seq_printf(m, "Render:\n"); head = &dev_priv->render_ring.active_list; break; + case BSD_LIST: + seq_printf(m, "BSD:\n"); + head = &dev_priv->bsd_ring.active_list; + break; case INACTIVE_LIST: seq_printf(m, "Inactive:\n"); head = &dev_priv->mm.inactive_list; @@ -974,7 +979,8 @@ static int i915_wedged_create(struct dentry *root, struct drm_minor *minor) static struct drm_info_list i915_debugfs_list[] = { {"i915_capabilities", i915_capabilities, 0, 0}, - {"i915_gem_active", i915_gem_object_list_info, 0, (void *) ACTIVE_LIST}, + {"i915_gem_render_active", i915_gem_object_list_info, 0, (void *) RENDER_LIST}, + {"i915_gem_bsd_active", i915_gem_object_list_info, 0, (void *) BSD_LIST}, {"i915_gem_flushing", i915_gem_object_list_info, 0, (void *) FLUSHING_LIST}, {"i915_gem_inactive", i915_gem_object_list_info, 0, (void *) INACTIVE_LIST}, {"i915_gem_pageflip", i915_gem_pageflip_info, 0}, -- cgit v1.1 From b84d5f0c22914d37d709add54c66e741c404fa56 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Sat, 18 Sep 2010 01:38:04 +0100 Subject: drm/i915: Inline i915_gem_ring_retire_request() Change the semantics to retire any buffer older than the current seqno rather than repeatedly calling calling the function to retire the buffer at the head of the list matching the request seqno. Whilst this should have no semantic impact on the implementation, Daniel was wondering if there was a bug where we might miss a retirement and so end up with a continually growing active list. Signed-off-by: Chris Wilson --- drivers/gpu/drm/i915/i915_gem.c | 91 +++++++++++++++++------------------------ 1 file changed, 38 insertions(+), 53 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index 71a2723..1c02798 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -1668,47 +1668,6 @@ i915_retire_commands(struct drm_device *dev, struct intel_ring_buffer *ring) } /** - * Moves buffers associated only with the given active seqno from the active - * to inactive list, potentially freeing them. - */ -static void -i915_gem_retire_request(struct drm_device *dev, - struct drm_i915_gem_request *request) -{ - trace_i915_gem_request_retire(dev, request->seqno); - - /* Move any buffers on the active list that are no longer referenced - * by the ringbuffer to the flushing/inactive lists as appropriate. - */ - while (!list_empty(&request->ring->active_list)) { - struct drm_gem_object *obj; - struct drm_i915_gem_object *obj_priv; - - obj_priv = list_first_entry(&request->ring->active_list, - struct drm_i915_gem_object, - list); - obj = &obj_priv->base; - - /* If the seqno being retired doesn't match the oldest in the - * list, then the oldest in the list must still be newer than - * this seqno. - */ - if (obj_priv->last_rendering_seqno != request->seqno) - return; - -#if WATCH_LRU - DRM_INFO("%s: retire %d moves to inactive list %p\n", - __func__, request->seqno, obj); -#endif - - if (obj->write_domain != 0) - i915_gem_object_move_to_flushing(obj); - else - i915_gem_object_move_to_inactive(obj); - } -} - -/** * Returns true if seq1 is later than seq2. */ bool @@ -1733,36 +1692,62 @@ i915_gem_retire_requests_ring(struct drm_device *dev, { drm_i915_private_t *dev_priv = dev->dev_private; uint32_t seqno; + bool wedged; - if (!ring->status_page.page_addr - || list_empty(&ring->request_list)) + if (!ring->status_page.page_addr || + list_empty(&ring->request_list)) return; seqno = i915_get_gem_seqno(dev, ring); + wedged = atomic_read(&dev_priv->mm.wedged); while (!list_empty(&ring->request_list)) { struct drm_i915_gem_request *request; - uint32_t retiring_seqno; request = list_first_entry(&ring->request_list, struct drm_i915_gem_request, list); - retiring_seqno = request->seqno; - if (i915_seqno_passed(seqno, retiring_seqno) || - atomic_read(&dev_priv->mm.wedged)) { - i915_gem_retire_request(dev, request); + if (!wedged && !i915_seqno_passed(seqno, request->seqno)) + break; + + trace_i915_gem_request_retire(dev, request->seqno); + + list_del(&request->list); + list_del(&request->client_list); + kfree(request); + } + + /* Move any buffers on the active list that are no longer referenced + * by the ringbuffer to the flushing/inactive lists as appropriate. + */ + while (!list_empty(&ring->active_list)) { + struct drm_gem_object *obj; + struct drm_i915_gem_object *obj_priv; + + obj_priv = list_first_entry(&ring->active_list, + struct drm_i915_gem_object, + list); - list_del(&request->list); - list_del(&request->client_list); - kfree(request); - } else + if (!wedged && + !i915_seqno_passed(seqno, obj_priv->last_rendering_seqno)) break; + + obj = &obj_priv->base; + +#if WATCH_LRU + DRM_INFO("%s: retire %d moves to inactive list %p\n", + __func__, request->seqno, obj); +#endif + + if (obj->write_domain != 0) + i915_gem_object_move_to_flushing(obj); + else + i915_gem_object_move_to_inactive(obj); } if (unlikely (dev_priv->trace_irq_seqno && i915_seqno_passed(dev_priv->trace_irq_seqno, seqno))) { - ring->user_irq_put(dev, ring); dev_priv->trace_irq_seqno = 0; } -- cgit v1.1 From 9220434a8768902cd9cf248709972678b74aa8c1 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Sat, 18 Sep 2010 11:02:01 +0100 Subject: drm/i915: Only emit a flush request on the active ring. When flushing the GPU domains,we emit a flush on *both* rings, even though they share a unified cache. Only emit the flush on the currently active ring. Signed-off-by: Chris Wilson --- drivers/gpu/drm/i915/i915_drv.h | 5 ++- drivers/gpu/drm/i915/i915_gem.c | 58 ++++++++++++++++++++++++--------- drivers/gpu/drm/i915/intel_ringbuffer.c | 6 ++-- drivers/gpu/drm/i915/intel_ringbuffer.h | 4 +++ 4 files changed, 51 insertions(+), 22 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 4b6aeb5..ed09846 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -623,6 +623,8 @@ typedef struct drm_i915_private { /* storage for physical objects */ struct drm_i915_gem_phys_object *phys_objs[I915_MAX_PHYS_OBJECT]; + + uint32_t flush_rings; } mm; struct sdvo_device_mapping sdvo_mappings[2]; /* indicate whether the LVDS_BORDER should be enabled or not */ @@ -1014,9 +1016,6 @@ int i915_do_wait_request(struct drm_device *dev, bool interruptible, struct intel_ring_buffer *ring); int i915_gem_fault(struct vm_area_struct *vma, struct vm_fault *vmf); -void i915_gem_process_flushing_list(struct drm_device *dev, - uint32_t flush_domains, - struct intel_ring_buffer *ring); int i915_gem_object_set_to_gtt_domain(struct drm_gem_object *obj, int write); int i915_gem_object_set_to_display_plane(struct drm_gem_object *obj, diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index 1c02798..cf27655 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -1567,7 +1567,7 @@ i915_gem_object_move_to_inactive(struct drm_gem_object *obj) i915_verify_inactive(dev, __FILE__, __LINE__); } -void +static void i915_gem_process_flushing_list(struct drm_device *dev, uint32_t flush_domains, struct intel_ring_buffer *ring) @@ -1880,23 +1880,36 @@ i915_wait_request(struct drm_device *dev, uint32_t seqno, } static void +i915_gem_flush_ring(struct drm_device *dev, + struct intel_ring_buffer *ring, + uint32_t invalidate_domains, + uint32_t flush_domains) +{ + ring->flush(dev, ring, invalidate_domains, flush_domains); + i915_gem_process_flushing_list(dev, flush_domains, ring); +} + +static void i915_gem_flush(struct drm_device *dev, uint32_t invalidate_domains, - uint32_t flush_domains) + uint32_t flush_domains, + uint32_t flush_rings) { drm_i915_private_t *dev_priv = dev->dev_private; if (flush_domains & I915_GEM_DOMAIN_CPU) drm_agp_chipset_flush(dev); - dev_priv->render_ring.flush(dev, &dev_priv->render_ring, - invalidate_domains, - flush_domains); - - if (HAS_BSD(dev)) - dev_priv->bsd_ring.flush(dev, &dev_priv->bsd_ring, - invalidate_domains, - flush_domains); + if ((flush_domains | invalidate_domains) & I915_GEM_GPU_DOMAINS) { + if (flush_rings & RING_RENDER) + i915_gem_flush_ring(dev, + &dev_priv->render_ring, + invalidate_domains, flush_domains); + if (flush_rings & RING_BSD) + i915_gem_flush_ring(dev, + &dev_priv->bsd_ring, + invalidate_domains, flush_domains); + } } /** @@ -2022,7 +2035,9 @@ i915_gpu_idle(struct drm_device *dev) return 0; /* Flush everything onto the inactive list. */ - i915_gem_flush(dev, I915_GEM_GPU_DOMAINS, I915_GEM_GPU_DOMAINS); + i915_gem_flush_ring(dev, + &dev_priv->render_ring, + I915_GEM_GPU_DOMAINS, I915_GEM_GPU_DOMAINS); ret = i915_wait_request(dev, i915_gem_next_request_seqno(dev, &dev_priv->render_ring), @@ -2031,6 +2046,10 @@ i915_gpu_idle(struct drm_device *dev) return ret; if (HAS_BSD(dev)) { + i915_gem_flush_ring(dev, + &dev_priv->bsd_ring, + I915_GEM_GPU_DOMAINS, I915_GEM_GPU_DOMAINS); + ret = i915_wait_request(dev, i915_gem_next_request_seqno(dev, &dev_priv->bsd_ring), &dev_priv->bsd_ring); @@ -2598,7 +2617,9 @@ i915_gem_object_flush_gpu_write_domain(struct drm_gem_object *obj, /* Queue the GPU write cache flushing we need. */ old_write_domain = obj->write_domain; - i915_gem_flush(dev, 0, obj->write_domain); + i915_gem_flush_ring(dev, + to_intel_bo(obj)->ring, + 0, obj->write_domain); BUG_ON(obj->write_domain); trace_i915_gem_object_change_domain(obj, @@ -2908,6 +2929,7 @@ static void i915_gem_object_set_to_gpu_domain(struct drm_gem_object *obj) { struct drm_device *dev = obj->dev; + struct drm_i915_private *dev_priv = dev->dev_private; struct drm_i915_gem_object *obj_priv = to_intel_bo(obj); uint32_t invalidate_domains = 0; uint32_t flush_domains = 0; @@ -2972,6 +2994,8 @@ i915_gem_object_set_to_gpu_domain(struct drm_gem_object *obj) dev->invalidate_domains |= invalidate_domains; dev->flush_domains |= flush_domains; + if (obj_priv->ring) + dev_priv->mm.flush_rings |= obj_priv->ring->id; #if WATCH_BUF DRM_INFO("%s: read %08x write %08x invalidate %08x flush %08x\n", __func__, @@ -3684,6 +3708,7 @@ i915_gem_do_execbuffer(struct drm_device *dev, void *data, */ dev->invalidate_domains = 0; dev->flush_domains = 0; + dev_priv->mm.flush_rings = 0; for (i = 0; i < args->buffer_count; i++) { struct drm_gem_object *obj = object_list[i]; @@ -3703,7 +3728,8 @@ i915_gem_do_execbuffer(struct drm_device *dev, void *data, #endif i915_gem_flush(dev, dev->invalidate_domains, - dev->flush_domains); + dev->flush_domains, + dev_priv->mm.flush_rings); } if (dev_priv->render_ring.outstanding_lazy_request) { @@ -4170,8 +4196,10 @@ i915_gem_busy_ioctl(struct drm_device *dev, void *data, * use this buffer rather sooner than later, so issuing the required * flush earlier is beneficial. */ - if (obj->write_domain) { - i915_gem_flush(dev, 0, obj->write_domain); + if (obj->write_domain & I915_GEM_GPU_DOMAINS) { + i915_gem_flush_ring(dev, + obj_priv->ring, + 0, obj->write_domain); (void)i915_add_request(dev, file_priv, NULL, obj_priv->ring); } diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.c b/drivers/gpu/drm/i915/intel_ringbuffer.c index 670f94a..45f66e2 100644 --- a/drivers/gpu/drm/i915/intel_ringbuffer.c +++ b/drivers/gpu/drm/i915/intel_ringbuffer.c @@ -116,8 +116,6 @@ render_ring_flush(struct drm_device *dev, intel_ring_emit(dev, ring, MI_NOOP); intel_ring_advance(dev, ring); } - - i915_gem_process_flushing_list(dev, flush_domains, ring); } static unsigned int render_ring_get_head(struct drm_device *dev, @@ -386,8 +384,6 @@ bsd_ring_flush(struct drm_device *dev, intel_ring_emit(dev, ring, MI_FLUSH); intel_ring_emit(dev, ring, MI_NOOP); intel_ring_advance(dev, ring); - - i915_gem_process_flushing_list(dev, flush_domains, ring); } static inline unsigned int bsd_ring_get_head(struct drm_device *dev, @@ -799,6 +795,7 @@ void intel_fill_struct(struct drm_device *dev, struct intel_ring_buffer render_ring = { .name = "render ring", + .id = RING_RENDER, .regs = { .ctl = PRB0_CTL, .head = PRB0_HEAD, @@ -836,6 +833,7 @@ struct intel_ring_buffer render_ring = { struct intel_ring_buffer bsd_ring = { .name = "bsd ring", + .id = RING_BSD, .regs = { .ctl = BSD_RING_CTL, .head = BSD_RING_HEAD, diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.h b/drivers/gpu/drm/i915/intel_ringbuffer.h index fa5d84f..8dc0e62 100644 --- a/drivers/gpu/drm/i915/intel_ringbuffer.h +++ b/drivers/gpu/drm/i915/intel_ringbuffer.h @@ -10,6 +10,10 @@ struct intel_hw_status_page { struct drm_i915_gem_execbuffer2; struct intel_ring_buffer { const char *name; + enum intel_ring_id { + RING_RENDER = 0x1, + RING_BSD = 0x2, + } id; struct ring_regs { u32 ctl; u32 head; -- cgit v1.1 From 9375e446e7f43be9a7c21e246cee35ea912532ec Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Sun, 19 Sep 2010 12:21:28 +0100 Subject: drm/i915: Clear flushing lists on GPU reset Owain Ainsworth noticed that the reset code failed to clear the flushing list leaving the driver in an inconsistent state following a hung GPU. Signed-off-by: Chris Wilson --- drivers/gpu/drm/i915/i915_drv.c | 6 ++++++ drivers/gpu/drm/i915/i915_drv.h | 1 + drivers/gpu/drm/i915/i915_gem.c | 16 ++++++++++++++++ 3 files changed, 23 insertions(+) diff --git a/drivers/gpu/drm/i915/i915_drv.c b/drivers/gpu/drm/i915/i915_drv.c index e58e917..cb1ddc6 100644 --- a/drivers/gpu/drm/i915/i915_drv.c +++ b/drivers/gpu/drm/i915/i915_drv.c @@ -385,6 +385,12 @@ int i965_reset(struct drm_device *dev, u8 flags) */ i915_gem_retire_requests(dev); + /* Remove anything from the flushing lists. The GPU cache is likely + * to be lost on reset along with the data, so simply move the + * lost bo to the inactive list. + */ + i915_gem_reset_flushing_list(dev); + /* * Set the domains we want to reset (GRDOM/bits 2 and 3) as * well as the reset bit (GR/bit 0). Setting the GR bit diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index ed09846..50fcb91 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -997,6 +997,7 @@ int i915_gem_object_get_fence_reg(struct drm_gem_object *obj, int i915_gem_object_put_fence_reg(struct drm_gem_object *obj, bool interruptible); void i915_gem_retire_requests(struct drm_device *dev); +void i915_gem_reset_flushing_list(struct drm_device *dev); void i915_gem_clflush_object(struct drm_gem_object *obj); int i915_gem_object_set_domain(struct drm_gem_object *obj, uint32_t read_domains, diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index cf27655..4e978e4 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -1683,6 +1683,22 @@ i915_get_gem_seqno(struct drm_device *dev, return ring->get_gem_seqno(dev, ring); } +void i915_gem_reset_flushing_list(struct drm_device *dev) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + + while (!list_empty(&dev_priv->mm.flushing_list)) { + struct drm_i915_gem_object *obj_priv; + + obj_priv = list_first_entry(&dev_priv->mm.flushing_list, + struct drm_i915_gem_object, + list); + + obj_priv->base.write_domain = 0; + i915_gem_object_move_to_inactive(&obj_priv->base); + } +} + /** * This function clears the request list as sequence numbers are passed. */ -- cgit v1.1 From 77f01230223a08792f5320ebba27af9cbb81b0cf Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Sun, 19 Sep 2010 12:31:36 +0100 Subject: drm/i915: Clear GPU read domains on reset Clear the GPU read domain for the inactive objects on a reset so that they are correctly invalidated on reuse. Signed-off-by: Chris Wilson --- drivers/gpu/drm/i915/i915_drv.c | 5 +++++ drivers/gpu/drm/i915/i915_drv.h | 1 + drivers/gpu/drm/i915/i915_gem.c | 13 +++++++++++++ 3 files changed, 19 insertions(+) diff --git a/drivers/gpu/drm/i915/i915_drv.c b/drivers/gpu/drm/i915/i915_drv.c index cb1ddc6..38e889b 100644 --- a/drivers/gpu/drm/i915/i915_drv.c +++ b/drivers/gpu/drm/i915/i915_drv.c @@ -391,6 +391,11 @@ int i965_reset(struct drm_device *dev, u8 flags) */ i915_gem_reset_flushing_list(dev); + /* Move everything out of the GPU domains to ensure we do any + * necessary invalidation upon reuse. + */ + i915_gem_reset_inactive_gpu_domains(dev); + /* * Set the domains we want to reset (GRDOM/bits 2 and 3) as * well as the reset bit (GR/bit 0). Setting the GR bit diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 50fcb91..ae05008 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -998,6 +998,7 @@ int i915_gem_object_put_fence_reg(struct drm_gem_object *obj, bool interruptible); void i915_gem_retire_requests(struct drm_device *dev); void i915_gem_reset_flushing_list(struct drm_device *dev); +void i915_gem_reset_inactive_gpu_domains(struct drm_device *dev); void i915_gem_clflush_object(struct drm_gem_object *obj); int i915_gem_object_set_domain(struct drm_gem_object *obj, uint32_t read_domains, diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index 4e978e4..325f52b 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -1699,6 +1699,19 @@ void i915_gem_reset_flushing_list(struct drm_device *dev) } } +void i915_gem_reset_inactive_gpu_domains(struct drm_device *dev) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + struct drm_i915_gem_object *obj_priv; + + list_for_each_entry(obj_priv, + &dev_priv->mm.inactive_list, + list) + { + obj_priv->base.read_domains &= ~I915_GEM_GPU_DOMAINS; + } +} + /** * This function clears the request list as sequence numbers are passed. */ -- cgit v1.1 From f803aa5532d14efc463abbeae10faa115c457a07 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Sun, 19 Sep 2010 12:38:26 +0100 Subject: drm/i915: Clean up bo lists on all hung gpus Previously we only tidied up the active bo lists for chipsets were we would attempt to reset the GPU. However, this action is necessary for the system to continue and reclaim the dead bo for all chipsets. Pointed out, in passing, by Owain Ainsworth. Signed-off-by: Chris Wilson --- drivers/gpu/drm/i915/i915_drv.c | 15 ++++++++++----- drivers/gpu/drm/i915/i915_drv.h | 2 +- drivers/gpu/drm/i915/i915_irq.c | 18 +++++------------- 3 files changed, 16 insertions(+), 19 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_drv.c b/drivers/gpu/drm/i915/i915_drv.c index 38e889b..2ddac06 100644 --- a/drivers/gpu/drm/i915/i915_drv.c +++ b/drivers/gpu/drm/i915/i915_drv.c @@ -368,7 +368,7 @@ static int ironlake_do_reset(struct drm_device *dev, u8 flags) * - re-init interrupt state * - re-init display */ -int i965_reset(struct drm_device *dev, u8 flags) +int i915_reset(struct drm_device *dev, u8 flags) { drm_i915_private_t *dev_priv = dev->dev_private; /* @@ -401,14 +401,19 @@ int i965_reset(struct drm_device *dev, u8 flags) * well as the reset bit (GR/bit 0). Setting the GR bit * triggers the reset; when done, the hardware will clear it. */ - if (IS_IRONLAKE(dev)) + ret = -ENODEV; + switch (INTEL_INFO(dev)->gen) { + case 5: ret = ironlake_do_reset(dev, flags); - else + break; + case 4: ret = i965_do_reset(dev, flags); + break; + } if (ret) { - WARN(true, "i915: Failed to reset chip\n"); + DRM_ERROR("Failed to reset chip.\n"); mutex_unlock(&dev->struct_mutex); - return -EIO; + return ret; } /* Ok, now get things going again... */ diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index ae05008..b57e049a 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -874,7 +874,7 @@ extern long i915_compat_ioctl(struct file *filp, unsigned int cmd, extern int i915_emit_box(struct drm_device *dev, struct drm_clip_rect *boxes, int i, int DR1, int DR4); -extern int i965_reset(struct drm_device *dev, u8 flags); +extern int i915_reset(struct drm_device *dev, u8 flags); extern unsigned long i915_chipset_val(struct drm_i915_private *dev_priv); extern unsigned long i915_mch_val(struct drm_i915_private *dev_priv); extern unsigned long i915_gfx_val(struct drm_i915_private *dev_priv); diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c index a5197e1..b1e7655 100644 --- a/drivers/gpu/drm/i915/i915_irq.c +++ b/drivers/gpu/drm/i915/i915_irq.c @@ -397,19 +397,11 @@ static void i915_error_work_func(struct work_struct *work) kobject_uevent_env(&dev->primary->kdev.kobj, KOBJ_CHANGE, error_event); if (atomic_read(&dev_priv->mm.wedged)) { - switch (INTEL_INFO(dev)->gen) { - case 5: - case 4: - DRM_DEBUG_DRIVER("resetting chip\n"); - kobject_uevent_env(&dev->primary->kdev.kobj, KOBJ_CHANGE, reset_event); - if (!i965_reset(dev, GRDOM_RENDER)) { - atomic_set(&dev_priv->mm.wedged, 0); - kobject_uevent_env(&dev->primary->kdev.kobj, KOBJ_CHANGE, reset_done_event); - } - break; - default: - DRM_DEBUG_DRIVER("reboot required\n"); - break; + DRM_DEBUG_DRIVER("resetting chip\n"); + kobject_uevent_env(&dev->primary->kdev.kobj, KOBJ_CHANGE, reset_event); + if (!i915_reset(dev, GRDOM_RENDER)) { + atomic_set(&dev_priv->mm.wedged, 0); + kobject_uevent_env(&dev->primary->kdev.kobj, KOBJ_CHANGE, reset_done_event); } } } -- cgit v1.1 From 92f49d9cec0052e09d938ac913d8e9ab432a0584 Mon Sep 17 00:00:00 2001 From: "Xiang, Haihao" Date: Thu, 16 Sep 2010 10:43:10 +0800 Subject: drm/i915: fix HAS_BSD with a device info flag Signed-off-by: Xiang, Haihao Reviewed-by: Chris Wilson Signed-off-by: Chris Wilson --- drivers/gpu/drm/i915/i915_drv.c | 4 ++++ drivers/gpu/drm/i915/i915_drv.h | 3 ++- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/i915_drv.c b/drivers/gpu/drm/i915/i915_drv.c index 2ddac06..393696c 100644 --- a/drivers/gpu/drm/i915/i915_drv.c +++ b/drivers/gpu/drm/i915/i915_drv.c @@ -125,6 +125,7 @@ static const struct intel_device_info intel_g33_info = { static const struct intel_device_info intel_g45_info = { .gen = 4, .is_g4x = 1, .need_gfx_hws = 1, .has_pipe_cxsr = 1, .has_hotplug = 1, + .has_bsd_ring = 1, }; static const struct intel_device_info intel_gm45_info = { @@ -132,6 +133,7 @@ static const struct intel_device_info intel_gm45_info = { .is_mobile = 1, .need_gfx_hws = 1, .has_fbc = 1, .has_rc6 = 1, .has_pipe_cxsr = 1, .has_hotplug = 1, .supports_tv = 1, + .has_bsd_ring = 1, }; static const struct intel_device_info intel_pineview_info = { @@ -143,11 +145,13 @@ static const struct intel_device_info intel_pineview_info = { static const struct intel_device_info intel_ironlake_d_info = { .gen = 5, .is_ironlake = 1, .need_gfx_hws = 1, .has_pipe_cxsr = 1, .has_hotplug = 1, + .has_bsd_ring = 1, }; static const struct intel_device_info intel_ironlake_m_info = { .gen = 5, .is_ironlake = 1, .is_mobile = 1, .need_gfx_hws = 1, .has_fbc = 1, .has_rc6 = 1, .has_hotplug = 1, + .has_bsd_ring = 1, }; static const struct intel_device_info intel_sandybridge_d_info = { diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index b57e049a..4b68120 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -214,6 +214,7 @@ struct intel_device_info { u8 has_overlay : 1; u8 overlay_needs_physical : 1; u8 supports_tv : 1; + u8 has_bsd_ring : 1; }; enum no_fbc_reason { @@ -1237,7 +1238,7 @@ static inline void i915_write(struct drm_i915_private *dev_priv, u32 reg, #define IS_GEN5(dev) (INTEL_INFO(dev)->gen == 5) #define IS_GEN6(dev) (INTEL_INFO(dev)->gen == 6) -#define HAS_BSD(dev) (IS_IRONLAKE(dev) || IS_G4X(dev)) +#define HAS_BSD(dev) (INTEL_INFO(dev)->has_bsd_ring) #define I915_NEED_GFX_HWS(dev) (INTEL_INFO(dev)->need_gfx_hws) #define HAS_OVERLAY(dev) (INTEL_INFO(dev)->has_overlay) -- cgit v1.1 From 5c1143bbecf50184ff7cad6287b4e0993bacbd9f Mon Sep 17 00:00:00 2001 From: "Xiang, Haihao" Date: Thu, 16 Sep 2010 10:43:11 +0800 Subject: drm/i915: do not export the instances of struct intel_ring_buffer Introduce intel_init_render_ring_buffer(), intel_init_bsd_ring_buffer for ring initialization. Signed-off-by: Xiang, Haihao Reviewed-by: Chris Wilson Signed-off-by: Chris Wilson --- drivers/gpu/drm/i915/i915_gem.c | 14 ++------------ drivers/gpu/drm/i915/intel_ringbuffer.c | 29 +++++++++++++++++++++++++++-- drivers/gpu/drm/i915/intel_ringbuffer.h | 4 ++-- 3 files changed, 31 insertions(+), 16 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index 325f52b..7b33b4d 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -4496,28 +4496,18 @@ i915_gem_init_ringbuffer(struct drm_device *dev) drm_i915_private_t *dev_priv = dev->dev_private; int ret; - dev_priv->render_ring = render_ring; - - if (!I915_NEED_GFX_HWS(dev)) { - dev_priv->render_ring.status_page.page_addr - = dev_priv->status_page_dmah->vaddr; - memset(dev_priv->render_ring.status_page.page_addr, - 0, PAGE_SIZE); - } - if (HAS_PIPE_CONTROL(dev)) { ret = i915_gem_init_pipe_control(dev); if (ret) return ret; } - ret = intel_init_ring_buffer(dev, &dev_priv->render_ring); + ret = intel_init_render_ring_buffer(dev); if (ret) goto cleanup_pipe_control; if (HAS_BSD(dev)) { - dev_priv->bsd_ring = bsd_ring; - ret = intel_init_ring_buffer(dev, &dev_priv->bsd_ring); + ret = intel_init_bsd_ring_buffer(dev); if (ret) goto cleanup_render_ring; } diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.c b/drivers/gpu/drm/i915/intel_ringbuffer.c index 45f66e2..178e2ce 100644 --- a/drivers/gpu/drm/i915/intel_ringbuffer.c +++ b/drivers/gpu/drm/i915/intel_ringbuffer.c @@ -793,7 +793,7 @@ void intel_fill_struct(struct drm_device *dev, intel_ring_advance(dev, ring); } -struct intel_ring_buffer render_ring = { +static struct intel_ring_buffer render_ring = { .name = "render ring", .id = RING_RENDER, .regs = { @@ -831,7 +831,7 @@ struct intel_ring_buffer render_ring = { /* ring buffer for bit-stream decoder */ -struct intel_ring_buffer bsd_ring = { +static struct intel_ring_buffer bsd_ring = { .name = "bsd ring", .id = RING_BSD, .regs = { @@ -866,3 +866,28 @@ struct intel_ring_buffer bsd_ring = { .status_page = {NULL, 0, NULL}, .map = {0,} }; + +int intel_init_render_ring_buffer(struct drm_device *dev) +{ + drm_i915_private_t *dev_priv = dev->dev_private; + + dev_priv->render_ring = render_ring; + + if (!I915_NEED_GFX_HWS(dev)) { + dev_priv->render_ring.status_page.page_addr + = dev_priv->status_page_dmah->vaddr; + memset(dev_priv->render_ring.status_page.page_addr, + 0, PAGE_SIZE); + } + + return intel_init_ring_buffer(dev, &dev_priv->render_ring); +} + +int intel_init_bsd_ring_buffer(struct drm_device *dev) +{ + drm_i915_private_t *dev_priv = dev->dev_private; + + dev_priv->bsd_ring = bsd_ring; + + return intel_init_ring_buffer(dev, &dev_priv->bsd_ring); +} diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.h b/drivers/gpu/drm/i915/intel_ringbuffer.h index 8dc0e62..5603d6e 100644 --- a/drivers/gpu/drm/i915/intel_ringbuffer.h +++ b/drivers/gpu/drm/i915/intel_ringbuffer.h @@ -133,7 +133,7 @@ void intel_ring_advance(struct drm_device *dev, u32 intel_ring_get_seqno(struct drm_device *dev, struct intel_ring_buffer *ring); -extern struct intel_ring_buffer render_ring; -extern struct intel_ring_buffer bsd_ring; +int intel_init_render_ring_buffer(struct drm_device *dev); +int intel_init_bsd_ring_buffer(struct drm_device *dev); #endif /* _INTEL_RINGBUFFER_H_ */ -- cgit v1.1 From d46eefa29724b1be0e8e90a3a51a190b912ebfab Mon Sep 17 00:00:00 2001 From: "Xiang, Haihao" Date: Thu, 16 Sep 2010 10:43:12 +0800 Subject: drm/i915: add set_tail hook in struct intel_ring_buffer This is prepared for video codec ring buffer on Sandybridge. It is needed to read/write more than one register to move the tail pointer of the video codec ring on Sandybridge. Signed-off-by: Xiang, Haihao Reviewed-by: Chris Wilson Signed-off-by: Chris Wilson --- drivers/gpu/drm/i915/intel_ringbuffer.c | 22 +++++++++++++++++----- drivers/gpu/drm/i915/intel_ringbuffer.h | 2 ++ 2 files changed, 19 insertions(+), 5 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.c b/drivers/gpu/drm/i915/intel_ringbuffer.c index 178e2ce..7debb19 100644 --- a/drivers/gpu/drm/i915/intel_ringbuffer.c +++ b/drivers/gpu/drm/i915/intel_ringbuffer.c @@ -132,6 +132,12 @@ static unsigned int render_ring_get_tail(struct drm_device *dev, return I915_READ(PRB0_TAIL) & TAIL_ADDR; } +static inline void render_ring_set_tail(struct drm_device *dev, u32 value) +{ + drm_i915_private_t *dev_priv = dev->dev_private; + I915_WRITE(PRB0_TAIL, value); +} + static unsigned int render_ring_get_active_head(struct drm_device *dev, struct intel_ring_buffer *ring) { @@ -144,8 +150,7 @@ static unsigned int render_ring_get_active_head(struct drm_device *dev, static void render_ring_advance_ring(struct drm_device *dev, struct intel_ring_buffer *ring) { - drm_i915_private_t *dev_priv = dev->dev_private; - I915_WRITE(PRB0_TAIL, ring->tail); + render_ring_set_tail(dev, ring->tail); } static int init_ring_common(struct drm_device *dev, @@ -159,7 +164,7 @@ static int init_ring_common(struct drm_device *dev, /* Stop the ring if it's running. */ I915_WRITE(ring->regs.ctl, 0); I915_WRITE(ring->regs.head, 0); - I915_WRITE(ring->regs.tail, 0); + ring->set_tail(dev, 0); /* Initialize the ring. */ I915_WRITE(ring->regs.start, obj_priv->gtt_offset); @@ -400,6 +405,12 @@ static inline unsigned int bsd_ring_get_tail(struct drm_device *dev, return I915_READ(BSD_RING_TAIL) & TAIL_ADDR; } +static inline void bsd_ring_set_tail(struct drm_device *dev, u32 value) +{ + drm_i915_private_t *dev_priv = dev->dev_private; + I915_WRITE(BSD_RING_TAIL, value); +} + static inline unsigned int bsd_ring_get_active_head(struct drm_device *dev, struct intel_ring_buffer *ring) { @@ -410,8 +421,7 @@ static inline unsigned int bsd_ring_get_active_head(struct drm_device *dev, static inline void bsd_ring_advance_ring(struct drm_device *dev, struct intel_ring_buffer *ring) { - drm_i915_private_t *dev_priv = dev->dev_private; - I915_WRITE(BSD_RING_TAIL, ring->tail); + bsd_ring_set_tail(dev, ring->tail); } static int init_bsd_ring(struct drm_device *dev, @@ -817,6 +827,7 @@ static struct intel_ring_buffer render_ring = { .init = init_render_ring, .get_head = render_ring_get_head, .get_tail = render_ring_get_tail, + .set_tail = render_ring_set_tail, .get_active_head = render_ring_get_active_head, .advance_ring = render_ring_advance_ring, .flush = render_ring_flush, @@ -855,6 +866,7 @@ static struct intel_ring_buffer bsd_ring = { .init = init_bsd_ring, .get_head = bsd_ring_get_head, .get_tail = bsd_ring_get_tail, + .set_tail = bsd_ring_set_tail, .get_active_head = bsd_ring_get_active_head, .advance_ring = bsd_ring_advance_ring, .flush = bsd_ring_flush, diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.h b/drivers/gpu/drm/i915/intel_ringbuffer.h index 5603d6e..7bd571c 100644 --- a/drivers/gpu/drm/i915/intel_ringbuffer.h +++ b/drivers/gpu/drm/i915/intel_ringbuffer.h @@ -48,6 +48,8 @@ struct intel_ring_buffer { struct intel_ring_buffer *ring); unsigned int (*get_tail)(struct drm_device *dev, struct intel_ring_buffer *ring); + void (*set_tail)(struct drm_device *dev, + u32 value); unsigned int (*get_active_head)(struct drm_device *dev, struct intel_ring_buffer *ring); void (*advance_ring)(struct drm_device *dev, -- cgit v1.1 From a3f07cd53e31c1c27364e56266a541b9467c1895 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Sun, 19 Sep 2010 14:36:46 +0100 Subject: drm/i915/ringbuffer: Implement advance using set_tail As noted by Zhenyu, we can now simply replace the existing advance hook by calling the new set_tail function pointer directly. Signed-off-by: Chris Wilson --- drivers/gpu/drm/i915/intel_ringbuffer.c | 16 +--------------- drivers/gpu/drm/i915/intel_ringbuffer.h | 2 -- 2 files changed, 1 insertion(+), 17 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.c b/drivers/gpu/drm/i915/intel_ringbuffer.c index 7debb19..3f80f18 100644 --- a/drivers/gpu/drm/i915/intel_ringbuffer.c +++ b/drivers/gpu/drm/i915/intel_ringbuffer.c @@ -147,12 +147,6 @@ static unsigned int render_ring_get_active_head(struct drm_device *dev, return I915_READ(acthd_reg); } -static void render_ring_advance_ring(struct drm_device *dev, - struct intel_ring_buffer *ring) -{ - render_ring_set_tail(dev, ring->tail); -} - static int init_ring_common(struct drm_device *dev, struct intel_ring_buffer *ring) { @@ -418,12 +412,6 @@ static inline unsigned int bsd_ring_get_active_head(struct drm_device *dev, return I915_READ(BSD_RING_ACTHD); } -static inline void bsd_ring_advance_ring(struct drm_device *dev, - struct intel_ring_buffer *ring) -{ - bsd_ring_set_tail(dev, ring->tail); -} - static int init_bsd_ring(struct drm_device *dev, struct intel_ring_buffer *ring) { @@ -785,7 +773,7 @@ void intel_ring_advance(struct drm_device *dev, struct intel_ring_buffer *ring) { ring->tail &= ring->size - 1; - ring->advance_ring(dev, ring); + ring->set_tail(dev, ring->tail); } void intel_fill_struct(struct drm_device *dev, @@ -829,7 +817,6 @@ static struct intel_ring_buffer render_ring = { .get_tail = render_ring_get_tail, .set_tail = render_ring_set_tail, .get_active_head = render_ring_get_active_head, - .advance_ring = render_ring_advance_ring, .flush = render_ring_flush, .add_request = render_ring_add_request, .get_gem_seqno = render_ring_get_gem_seqno, @@ -868,7 +855,6 @@ static struct intel_ring_buffer bsd_ring = { .get_tail = bsd_ring_get_tail, .set_tail = bsd_ring_set_tail, .get_active_head = bsd_ring_get_active_head, - .advance_ring = bsd_ring_advance_ring, .flush = bsd_ring_flush, .add_request = bsd_ring_add_request, .get_gem_seqno = bsd_ring_get_gem_seqno, diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.h b/drivers/gpu/drm/i915/intel_ringbuffer.h index 7bd571c..be1fd9b 100644 --- a/drivers/gpu/drm/i915/intel_ringbuffer.h +++ b/drivers/gpu/drm/i915/intel_ringbuffer.h @@ -52,8 +52,6 @@ struct intel_ring_buffer { u32 value); unsigned int (*get_active_head)(struct drm_device *dev, struct intel_ring_buffer *ring); - void (*advance_ring)(struct drm_device *dev, - struct intel_ring_buffer *ring); void (*flush)(struct drm_device *dev, struct intel_ring_buffer *ring, u32 invalidate_domains, -- cgit v1.1 From 881f47b64723f4d697084533491a489e3e74b10f Mon Sep 17 00:00:00 2001 From: "Xiang, Haihao" Date: Sun, 19 Sep 2010 14:40:43 +0100 Subject: drm/i915: add a new BSD ring buffer for Sandybridge This ring buffer is used for video decoding/encoding on Sandybridge. Signed-off-by: Xiang, Haihao Reviewed-by: Chris Wilson Signed-off-by: Chris Wilson --- drivers/gpu/drm/i915/i915_drv.c | 2 + drivers/gpu/drm/i915/i915_irq.c | 15 ++-- drivers/gpu/drm/i915/i915_reg.h | 26 ++++++- drivers/gpu/drm/i915/intel_ringbuffer.c | 124 +++++++++++++++++++++++++++++++- 4 files changed, 159 insertions(+), 8 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_drv.c b/drivers/gpu/drm/i915/i915_drv.c index 393696c..2c87f9b 100644 --- a/drivers/gpu/drm/i915/i915_drv.c +++ b/drivers/gpu/drm/i915/i915_drv.c @@ -157,11 +157,13 @@ static const struct intel_device_info intel_ironlake_m_info = { static const struct intel_device_info intel_sandybridge_d_info = { .gen = 6, .need_gfx_hws = 1, .has_hotplug = 1, + .has_bsd_ring = 1, }; static const struct intel_device_info intel_sandybridge_m_info = { .gen = 6, .is_mobile = 1, .need_gfx_hws = 1, .has_hotplug = 1, + .has_bsd_ring = 1, }; static const struct pci_device_id pciidlist[] = { /* aka */ diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c index b1e7655..d4c053e 100644 --- a/drivers/gpu/drm/i915/i915_irq.c +++ b/drivers/gpu/drm/i915/i915_irq.c @@ -300,6 +300,10 @@ static irqreturn_t ironlake_irq_handler(struct drm_device *dev) u32 de_iir, gt_iir, de_ier, pch_iir; struct drm_i915_master_private *master_priv; struct intel_ring_buffer *render_ring = &dev_priv->render_ring; + u32 bsd_usr_interrupt = GT_BSD_USER_INTERRUPT; + + if (IS_GEN6(dev)) + bsd_usr_interrupt = GT_GEN6_BSD_USER_INTERRUPT; /* disable master interrupt before clearing iir */ de_ier = I915_READ(DEIER); @@ -331,10 +335,9 @@ static irqreturn_t ironlake_irq_handler(struct drm_device *dev) mod_timer(&dev_priv->hangcheck_timer, jiffies + msecs_to_jiffies(DRM_I915_HANGCHECK_PERIOD)); } - if (gt_iir & GT_BSD_USER_INTERRUPT) + if (gt_iir & bsd_usr_interrupt) DRM_WAKEUP(&dev_priv->bsd_ring.irq_queue); - if (de_iir & DE_GSE) intel_opregion_gse_intr(dev); @@ -1436,17 +1439,19 @@ static int ironlake_irq_postinstall(struct drm_device *dev) I915_WRITE(DEIER, dev_priv->de_irq_enable_reg); (void) I915_READ(DEIER); - /* Gen6 only needs render pipe_control now */ if (IS_GEN6(dev)) - render_mask = GT_PIPE_NOTIFY; + render_mask = GT_PIPE_NOTIFY | GT_GEN6_BSD_USER_INTERRUPT; dev_priv->gt_irq_mask_reg = ~render_mask; dev_priv->gt_irq_enable_reg = render_mask; I915_WRITE(GTIIR, I915_READ(GTIIR)); I915_WRITE(GTIMR, dev_priv->gt_irq_mask_reg); - if (IS_GEN6(dev)) + if (IS_GEN6(dev)) { I915_WRITE(GEN6_RENDER_IMR, ~GEN6_RENDER_PIPE_CONTROL_NOTIFY_INTERRUPT); + I915_WRITE(GEN6_BSD_IMR, ~GEN6_BSD_IMR_USER_INTERRUPT); + } + I915_WRITE(GTIER, dev_priv->gt_irq_enable_reg); (void) I915_READ(GTIER); diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index b46e580..8d51de0 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -197,11 +197,11 @@ #define MI_STORE_DWORD_INDEX MI_INSTR(0x21, 1) #define MI_STORE_DWORD_INDEX_SHIFT 2 #define MI_LOAD_REGISTER_IMM MI_INSTR(0x22, 1) +#define MI_FLUSH_DW MI_INSTR(0x26, 2) /* for GEN6 */ #define MI_BATCH_BUFFER MI_INSTR(0x30, 1) #define MI_BATCH_NON_SECURE (1) #define MI_BATCH_NON_SECURE_I965 (1<<8) #define MI_BATCH_BUFFER_START MI_INSTR(0x31, 0) - /* * 3D instructions used by the kernel */ @@ -484,6 +484,28 @@ #define BSD_HWS_PGA 0x04080 /* + * video command stream instruction and interrupt control register defines + * for GEN6 + */ +#define GEN6_BSD_RING_TAIL 0x12030 +#define GEN6_BSD_RING_HEAD 0x12034 +#define GEN6_BSD_RING_START 0x12038 +#define GEN6_BSD_RING_CTL 0x1203c +#define GEN6_BSD_RING_ACTHD 0x12074 +#define GEN6_BSD_HWS_PGA 0x14080 + +#define GEN6_BSD_SLEEP_PSMI_CONTROL 0x12050 +#define GEN6_BSD_SLEEP_PSMI_CONTROL_RC_ILDL_MESSAGE_MODIFY_MASK (1 << 16) +#define GEN6_BSD_SLEEP_PSMI_CONTROL_RC_ILDL_MESSAGE_DISABLE (1 << 0) +#define GEN6_BSD_SLEEP_PSMI_CONTROL_RC_ILDL_MESSAGE_ENABLE 0 +#define GEN6_BSD_SLEEP_PSMI_CONTROL_IDLE_INDICATOR (1 << 3) + +#define GEN6_BSD_IMR 0x120a8 +#define GEN6_BSD_IMR_USER_INTERRUPT (1 << 12) + +#define GEN6_BSD_RNCID 0x12198 + +/* * Framebuffer compression (915+ only) */ @@ -2598,7 +2620,7 @@ #define GT_SYNC_STATUS (1 << 2) #define GT_USER_INTERRUPT (1 << 0) #define GT_BSD_USER_INTERRUPT (1 << 5) - +#define GT_GEN6_BSD_USER_INTERRUPT (1 << 12) #define GTISR 0x44010 #define GTIMR 0x44014 diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.c b/drivers/gpu/drm/i915/intel_ringbuffer.c index 3f80f18..478406d 100644 --- a/drivers/gpu/drm/i915/intel_ringbuffer.c +++ b/drivers/gpu/drm/i915/intel_ringbuffer.c @@ -32,6 +32,7 @@ #include "i915_drv.h" #include "i915_drm.h" #include "i915_trace.h" +#include "intel_drv.h" static u32 i915_gem_get_seqno(struct drm_device *dev) { @@ -865,6 +866,124 @@ static struct intel_ring_buffer bsd_ring = { .map = {0,} }; + +static void gen6_bsd_setup_status_page(struct drm_device *dev, + struct intel_ring_buffer *ring) +{ + drm_i915_private_t *dev_priv = dev->dev_private; + I915_WRITE(GEN6_BSD_HWS_PGA, ring->status_page.gfx_addr); + I915_READ(GEN6_BSD_HWS_PGA); +} + +static inline unsigned int gen6_bsd_ring_get_head(struct drm_device *dev, + struct intel_ring_buffer *ring) +{ + drm_i915_private_t *dev_priv = dev->dev_private; + return I915_READ(GEN6_BSD_RING_HEAD) & HEAD_ADDR; +} + +static inline unsigned int gen6_bsd_ring_get_tail(struct drm_device *dev, + struct intel_ring_buffer *ring) +{ + drm_i915_private_t *dev_priv = dev->dev_private; + return I915_READ(GEN6_BSD_RING_TAIL) & TAIL_ADDR; +} + +static inline void gen6_bsd_ring_set_tail(struct drm_device *dev, + u32 value) +{ + drm_i915_private_t *dev_priv = dev->dev_private; + + /* Every tail move must follow the sequence below */ + I915_WRITE(GEN6_BSD_SLEEP_PSMI_CONTROL, + GEN6_BSD_SLEEP_PSMI_CONTROL_RC_ILDL_MESSAGE_MODIFY_MASK | + GEN6_BSD_SLEEP_PSMI_CONTROL_RC_ILDL_MESSAGE_DISABLE); + I915_WRITE(GEN6_BSD_RNCID, 0x0); + + if (wait_for((I915_READ(GEN6_BSD_SLEEP_PSMI_CONTROL) & + GEN6_BSD_SLEEP_PSMI_CONTROL_IDLE_INDICATOR) == 0, + 50)) + DRM_ERROR("timed out waiting for IDLE Indicator\n"); + + I915_WRITE(GEN6_BSD_RING_TAIL, value); + I915_WRITE(GEN6_BSD_SLEEP_PSMI_CONTROL, + GEN6_BSD_SLEEP_PSMI_CONTROL_RC_ILDL_MESSAGE_MODIFY_MASK | + GEN6_BSD_SLEEP_PSMI_CONTROL_RC_ILDL_MESSAGE_ENABLE); +} + +static inline unsigned int gen6_bsd_ring_get_active_head(struct drm_device *dev, + struct intel_ring_buffer *ring) +{ + drm_i915_private_t *dev_priv = dev->dev_private; + return I915_READ(GEN6_BSD_RING_ACTHD); +} + +static void gen6_bsd_ring_flush(struct drm_device *dev, + struct intel_ring_buffer *ring, + u32 invalidate_domains, + u32 flush_domains) +{ + intel_ring_begin(dev, ring, 4); + intel_ring_emit(dev, ring, MI_FLUSH_DW); + intel_ring_emit(dev, ring, 0); + intel_ring_emit(dev, ring, 0); + intel_ring_emit(dev, ring, 0); + intel_ring_advance(dev, ring); +} + +static int +gen6_bsd_ring_dispatch_gem_execbuffer(struct drm_device *dev, + struct intel_ring_buffer *ring, + struct drm_i915_gem_execbuffer2 *exec, + struct drm_clip_rect *cliprects, + uint64_t exec_offset) +{ + uint32_t exec_start; + exec_start = (uint32_t) exec_offset + exec->batch_start_offset; + intel_ring_begin(dev, ring, 2); + intel_ring_emit(dev, ring, MI_BATCH_BUFFER_START | MI_BATCH_NON_SECURE_I965); /* bit0-7 is the length on GEN6+ */ + intel_ring_emit(dev, ring, exec_start); + intel_ring_advance(dev, ring); + return 0; +} + +/* ring buffer for Video Codec for Gen6+ */ +static struct intel_ring_buffer gen6_bsd_ring = { + .name = "gen6 bsd ring", + .id = RING_BSD, + .regs = { + .ctl = GEN6_BSD_RING_CTL, + .head = GEN6_BSD_RING_HEAD, + .tail = GEN6_BSD_RING_TAIL, + .start = GEN6_BSD_RING_START + }, + .size = 32 * PAGE_SIZE, + .alignment = PAGE_SIZE, + .virtual_start = NULL, + .dev = NULL, + .gem_object = NULL, + .head = 0, + .tail = 0, + .space = 0, + .user_irq_refcount = 0, + .irq_gem_seqno = 0, + .waiting_gem_seqno = 0, + .setup_status_page = gen6_bsd_setup_status_page, + .init = init_bsd_ring, + .get_head = gen6_bsd_ring_get_head, + .get_tail = gen6_bsd_ring_get_tail, + .set_tail = gen6_bsd_ring_set_tail, + .get_active_head = gen6_bsd_ring_get_active_head, + .flush = gen6_bsd_ring_flush, + .add_request = bsd_ring_add_request, + .get_gem_seqno = bsd_ring_get_gem_seqno, + .user_irq_get = bsd_ring_get_user_irq, + .user_irq_put = bsd_ring_put_user_irq, + .dispatch_gem_execbuffer = gen6_bsd_ring_dispatch_gem_execbuffer, + .status_page = {NULL, 0, NULL}, + .map = {0,} +}; + int intel_init_render_ring_buffer(struct drm_device *dev) { drm_i915_private_t *dev_priv = dev->dev_private; @@ -885,7 +1004,10 @@ int intel_init_bsd_ring_buffer(struct drm_device *dev) { drm_i915_private_t *dev_priv = dev->dev_private; - dev_priv->bsd_ring = bsd_ring; + if (IS_GEN6(dev)) + dev_priv->bsd_ring = gen6_bsd_ring; + else + dev_priv->bsd_ring = bsd_ring; return intel_init_ring_buffer(dev, &dev_priv->bsd_ring); } -- cgit v1.1 From e070868ef2101ce548d4fbb25edfd301e59fb719 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Sun, 19 Sep 2010 14:46:27 +0100 Subject: drm/i915/ringbuffer: Mark the initialisation structs as constant. Signed-off-by: Chris Wilson --- drivers/gpu/drm/i915/intel_ringbuffer.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.c b/drivers/gpu/drm/i915/intel_ringbuffer.c index 478406d..f0b44d3 100644 --- a/drivers/gpu/drm/i915/intel_ringbuffer.c +++ b/drivers/gpu/drm/i915/intel_ringbuffer.c @@ -792,7 +792,7 @@ void intel_fill_struct(struct drm_device *dev, intel_ring_advance(dev, ring); } -static struct intel_ring_buffer render_ring = { +static const struct intel_ring_buffer render_ring = { .name = "render ring", .id = RING_RENDER, .regs = { @@ -830,7 +830,7 @@ static struct intel_ring_buffer render_ring = { /* ring buffer for bit-stream decoder */ -static struct intel_ring_buffer bsd_ring = { +static const struct intel_ring_buffer bsd_ring = { .name = "bsd ring", .id = RING_BSD, .regs = { @@ -948,7 +948,7 @@ gen6_bsd_ring_dispatch_gem_execbuffer(struct drm_device *dev, } /* ring buffer for Video Codec for Gen6+ */ -static struct intel_ring_buffer gen6_bsd_ring = { +static const struct intel_ring_buffer gen6_bsd_ring = { .name = "gen6 bsd ring", .id = RING_BSD, .regs = { -- cgit v1.1 From c7f9f9a8b89bb4d53edc030f5b61ae11d6859721 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Sun, 19 Sep 2010 15:05:13 +0100 Subject: drm/i915: Use ring->flush() instead of MI_FLUSH Use the ring abstraction to hide the details of having choose the appropriate flushing method. Signed-off-by: Chris Wilson --- drivers/gpu/drm/i915/i915_drv.h | 4 ++++ drivers/gpu/drm/i915/i915_gem.c | 2 +- drivers/gpu/drm/i915/intel_display.c | 31 +++++++++++++++---------------- 3 files changed, 20 insertions(+), 17 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 4b68120..790ffec 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -1001,6 +1001,10 @@ void i915_gem_retire_requests(struct drm_device *dev); void i915_gem_reset_flushing_list(struct drm_device *dev); void i915_gem_reset_inactive_gpu_domains(struct drm_device *dev); void i915_gem_clflush_object(struct drm_gem_object *obj); +void i915_gem_flush_ring(struct drm_device *dev, + struct intel_ring_buffer *ring, + uint32_t invalidate_domains, + uint32_t flush_domains); int i915_gem_object_set_domain(struct drm_gem_object *obj, uint32_t read_domains, uint32_t write_domain); diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index 7b33b4d..b242530 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -1908,7 +1908,7 @@ i915_wait_request(struct drm_device *dev, uint32_t seqno, return i915_do_wait_request(dev, seqno, 1, ring); } -static void +void i915_gem_flush_ring(struct drm_device *dev, struct intel_ring_buffer *ring, uint32_t invalidate_domains, diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index c3f0400..0505ddb 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -5056,24 +5056,23 @@ static int intel_crtc_page_flip(struct drm_crtc *crtc, atomic_inc(&obj_priv->pending_flip); work->pending_flip_obj = obj; - if (was_dirty || IS_GEN3(dev) || IS_GEN2(dev)) { - BEGIN_LP_RING(2); - if (IS_GEN3(dev) || IS_GEN2(dev)) { - u32 flip_mask; + /* Schedule the pipelined flush */ + if (was_dirty) + i915_gem_flush_ring(dev, obj_priv->ring, 0, was_dirty); - /* Can't queue multiple flips, so wait for the previous - * one to finish before executing the next. - */ + if (IS_GEN3(dev) || IS_GEN2(dev)) { + u32 flip_mask; - if (intel_crtc->plane) - flip_mask = MI_WAIT_FOR_PLANE_B_FLIP; - else - flip_mask = MI_WAIT_FOR_PLANE_A_FLIP; - - OUT_RING(MI_WAIT_FOR_EVENT | flip_mask); - } else - OUT_RING(MI_NOOP); - OUT_RING(MI_FLUSH); + /* Can't queue multiple flips, so wait for the previous + * one to finish before executing the next. + */ + BEGIN_LP_RING(2); + if (intel_crtc->plane) + flip_mask = MI_WAIT_FOR_PLANE_B_FLIP; + else + flip_mask = MI_WAIT_FOR_PLANE_A_FLIP; + OUT_RING(MI_WAIT_FOR_EVENT | flip_mask); + OUT_RING(MI_NOOP); ADVANCE_LP_RING(); } -- cgit v1.1 From b8aea0c8003927f13e257c7ff370b6b73dbe2a5a Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Mon, 2 Aug 2010 15:28:30 +0200 Subject: drm/i915: kill duplicated/unneeded register defines This looks like a copy-paste remnant from the i810. All the regs that are actually used are already defined somewhere else in i915_reg.h! Signed-off-by: Daniel Vetter Signed-off-by: Chris Wilson --- drivers/gpu/drm/i915/i915_reg.h | 18 ------------------ 1 file changed, 18 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index 8d51de0..8b8ac60 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -709,24 +709,6 @@ #define ADPA_DPMS_STANDBY (2<<10) #define ADPA_DPMS_OFF (3<<10) -#define RING_TAIL 0x00 -#define TAIL_ADDR 0x001FFFF8 -#define RING_HEAD 0x04 -#define HEAD_WRAP_COUNT 0xFFE00000 -#define HEAD_WRAP_ONE 0x00200000 -#define HEAD_ADDR 0x001FFFFC -#define RING_START 0x08 -#define START_ADDR 0xFFFFF000 -#define RING_LEN 0x0C -#define RING_NR_PAGES 0x001FF000 -#define RING_REPORT_MASK 0x00000006 -#define RING_REPORT_64K 0x00000002 -#define RING_REPORT_128K 0x00000004 -#define RING_NO_REPORT 0x00000000 -#define RING_VALID_MASK 0x00000001 -#define RING_VALID 0x00000001 -#define RING_INVALID 0x00000000 - /* Scratch pad debug 0 reg: */ #define DPLL_FPA01_P1_POST_DIV_MASK_I830 0x001f0000 -- cgit v1.1 From 333e9fe94d00ce8c334d91099449b9948bf76b92 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Mon, 2 Aug 2010 16:24:01 +0200 Subject: drm/i915: add relative ring register macros Documentation explicitly mentions that the ring registers are designed to have the same offsets relative to a base registers. Use this to fight the code beaurocratic in intel_ringbuffer.c. No code changes in this patch, just the new definitions. Signed-off-by: Daniel Vetter Signed-off-by: Chris Wilson --- drivers/gpu/drm/i915/i915_reg.h | 8 ++++++++ drivers/gpu/drm/i915/intel_ringbuffer.c | 3 +++ drivers/gpu/drm/i915/intel_ringbuffer.h | 1 + 3 files changed, 12 insertions(+) diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index 8b8ac60..77c9191 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -288,6 +288,14 @@ #define PRB0_HEAD 0x02034 #define PRB0_START 0x02038 #define PRB0_CTL 0x0203c +#define RENDER_RING_BASE 0x02000 +#define BSD_RING_BASE 0x04000 +#define GEN6_BSD_RING_BASE 0x12000 +#define RING_TAIL(base) (base)+0x30 +#define RING_HEAD(base) (base)+0x34 +#define RING_START(base) (base)+0x38 +#define RING_CTL(base) (base)+0x3c +#define RING_HWS_PGA(base) (base)+0x80 #define TAIL_ADDR 0x001FFFF8 #define HEAD_WRAP_COUNT 0xFFE00000 #define HEAD_WRAP_ONE 0x00200000 diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.c b/drivers/gpu/drm/i915/intel_ringbuffer.c index f0b44d3..c1517b2 100644 --- a/drivers/gpu/drm/i915/intel_ringbuffer.c +++ b/drivers/gpu/drm/i915/intel_ringbuffer.c @@ -801,6 +801,7 @@ static const struct intel_ring_buffer render_ring = { .tail = PRB0_TAIL, .start = PRB0_START }, + .mmio_base = RENDER_RING_BASE, .size = 32 * PAGE_SIZE, .alignment = PAGE_SIZE, .virtual_start = NULL, @@ -839,6 +840,7 @@ static const struct intel_ring_buffer bsd_ring = { .tail = BSD_RING_TAIL, .start = BSD_RING_START }, + .mmio_base = BSD_RING_BASE, .size = 32 * PAGE_SIZE, .alignment = PAGE_SIZE, .virtual_start = NULL, @@ -957,6 +959,7 @@ static const struct intel_ring_buffer gen6_bsd_ring = { .tail = GEN6_BSD_RING_TAIL, .start = GEN6_BSD_RING_START }, + .mmio_base = GEN6_BSD_RING_BASE, .size = 32 * PAGE_SIZE, .alignment = PAGE_SIZE, .virtual_start = NULL, diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.h b/drivers/gpu/drm/i915/intel_ringbuffer.h index be1fd9b..3917d8b 100644 --- a/drivers/gpu/drm/i915/intel_ringbuffer.h +++ b/drivers/gpu/drm/i915/intel_ringbuffer.h @@ -20,6 +20,7 @@ struct intel_ring_buffer { u32 tail; u32 start; } regs; + u32 mmio_base; unsigned long size; unsigned int alignment; void *virtual_start; -- cgit v1.1 From 870e86ddc2d110124812b277643ed0f2767148ee Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Mon, 2 Aug 2010 16:29:44 +0200 Subject: drm/i915: use new macros to access the ring tail register Signed-off-by: Daniel Vetter Signed-off-by: Chris Wilson --- drivers/gpu/drm/i915/intel_ringbuffer.c | 63 +++++++++------------------------ drivers/gpu/drm/i915/intel_ringbuffer.h | 9 ++--- 2 files changed, 22 insertions(+), 50 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.c b/drivers/gpu/drm/i915/intel_ringbuffer.c index c1517b2..4b797e7 100644 --- a/drivers/gpu/drm/i915/intel_ringbuffer.c +++ b/drivers/gpu/drm/i915/intel_ringbuffer.c @@ -126,17 +126,12 @@ static unsigned int render_ring_get_head(struct drm_device *dev, return I915_READ(PRB0_HEAD) & HEAD_ADDR; } -static unsigned int render_ring_get_tail(struct drm_device *dev, - struct intel_ring_buffer *ring) -{ - drm_i915_private_t *dev_priv = dev->dev_private; - return I915_READ(PRB0_TAIL) & TAIL_ADDR; -} - -static inline void render_ring_set_tail(struct drm_device *dev, u32 value) +static void ring_set_tail(struct drm_device *dev, + struct intel_ring_buffer *ring, + u32 value) { drm_i915_private_t *dev_priv = dev->dev_private; - I915_WRITE(PRB0_TAIL, value); + I915_WRITE_TAIL(ring, ring->tail); } static unsigned int render_ring_get_active_head(struct drm_device *dev, @@ -159,7 +154,7 @@ static int init_ring_common(struct drm_device *dev, /* Stop the ring if it's running. */ I915_WRITE(ring->regs.ctl, 0); I915_WRITE(ring->regs.head, 0); - ring->set_tail(dev, 0); + ring->set_tail(dev, ring, 0); /* Initialize the ring. */ I915_WRITE(ring->regs.start, obj_priv->gtt_offset); @@ -172,7 +167,7 @@ static int init_ring_common(struct drm_device *dev, ring->name, I915_READ(ring->regs.ctl), I915_READ(ring->regs.head), - I915_READ(ring->regs.tail), + I915_READ_TAIL(ring), I915_READ(ring->regs.start)); I915_WRITE(ring->regs.head, 0); @@ -182,7 +177,7 @@ static int init_ring_common(struct drm_device *dev, ring->name, I915_READ(ring->regs.ctl), I915_READ(ring->regs.head), - I915_READ(ring->regs.tail), + I915_READ_TAIL(ring), I915_READ(ring->regs.start)); } @@ -198,7 +193,7 @@ static int init_ring_common(struct drm_device *dev, ring->name, I915_READ(ring->regs.ctl), I915_READ(ring->regs.head), - I915_READ(ring->regs.tail), + I915_READ_TAIL(ring), I915_READ(ring->regs.start)); return -EIO; } @@ -207,7 +202,7 @@ static int init_ring_common(struct drm_device *dev, i915_kernel_lost_context(dev); else { ring->head = ring->get_head(dev, ring); - ring->tail = ring->get_tail(dev, ring); + ring->tail = I915_READ_TAIL(ring) & TAIL_ADDR; ring->space = ring->head - (ring->tail + 8); if (ring->space < 0) ring->space += ring->size; @@ -393,19 +388,6 @@ static inline unsigned int bsd_ring_get_head(struct drm_device *dev, return I915_READ(BSD_RING_HEAD) & HEAD_ADDR; } -static inline unsigned int bsd_ring_get_tail(struct drm_device *dev, - struct intel_ring_buffer *ring) -{ - drm_i915_private_t *dev_priv = dev->dev_private; - return I915_READ(BSD_RING_TAIL) & TAIL_ADDR; -} - -static inline void bsd_ring_set_tail(struct drm_device *dev, u32 value) -{ - drm_i915_private_t *dev_priv = dev->dev_private; - I915_WRITE(BSD_RING_TAIL, value); -} - static inline unsigned int bsd_ring_get_active_head(struct drm_device *dev, struct intel_ring_buffer *ring) { @@ -620,6 +602,7 @@ err: int intel_init_ring_buffer(struct drm_device *dev, struct intel_ring_buffer *ring) { + struct drm_i915_private *dev_priv = dev->dev_private; struct drm_i915_gem_object *obj_priv; struct drm_gem_object *obj; int ret; @@ -668,7 +651,7 @@ int intel_init_ring_buffer(struct drm_device *dev, i915_kernel_lost_context(dev); else { ring->head = ring->get_head(dev, ring); - ring->tail = ring->get_tail(dev, ring); + ring->tail = I915_READ_TAIL(ring) & TAIL_ADDR; ring->space = ring->head - (ring->tail + 8); if (ring->space < 0) ring->space += ring->size; @@ -774,7 +757,7 @@ void intel_ring_advance(struct drm_device *dev, struct intel_ring_buffer *ring) { ring->tail &= ring->size - 1; - ring->set_tail(dev, ring->tail); + ring->set_tail(dev, ring, ring->tail); } void intel_fill_struct(struct drm_device *dev, @@ -798,7 +781,6 @@ static const struct intel_ring_buffer render_ring = { .regs = { .ctl = PRB0_CTL, .head = PRB0_HEAD, - .tail = PRB0_TAIL, .start = PRB0_START }, .mmio_base = RENDER_RING_BASE, @@ -816,8 +798,7 @@ static const struct intel_ring_buffer render_ring = { .setup_status_page = render_setup_status_page, .init = init_render_ring, .get_head = render_ring_get_head, - .get_tail = render_ring_get_tail, - .set_tail = render_ring_set_tail, + .set_tail = ring_set_tail, .get_active_head = render_ring_get_active_head, .flush = render_ring_flush, .add_request = render_ring_add_request, @@ -837,7 +818,6 @@ static const struct intel_ring_buffer bsd_ring = { .regs = { .ctl = BSD_RING_CTL, .head = BSD_RING_HEAD, - .tail = BSD_RING_TAIL, .start = BSD_RING_START }, .mmio_base = BSD_RING_BASE, @@ -855,8 +835,7 @@ static const struct intel_ring_buffer bsd_ring = { .setup_status_page = bsd_setup_status_page, .init = init_bsd_ring, .get_head = bsd_ring_get_head, - .get_tail = bsd_ring_get_tail, - .set_tail = bsd_ring_set_tail, + .set_tail = ring_set_tail, .get_active_head = bsd_ring_get_active_head, .flush = bsd_ring_flush, .add_request = bsd_ring_add_request, @@ -884,15 +863,9 @@ static inline unsigned int gen6_bsd_ring_get_head(struct drm_device *dev, return I915_READ(GEN6_BSD_RING_HEAD) & HEAD_ADDR; } -static inline unsigned int gen6_bsd_ring_get_tail(struct drm_device *dev, - struct intel_ring_buffer *ring) -{ - drm_i915_private_t *dev_priv = dev->dev_private; - return I915_READ(GEN6_BSD_RING_TAIL) & TAIL_ADDR; -} - static inline void gen6_bsd_ring_set_tail(struct drm_device *dev, - u32 value) + struct intel_ring_buffer *ring, + u32 value) { drm_i915_private_t *dev_priv = dev->dev_private; @@ -907,7 +880,7 @@ static inline void gen6_bsd_ring_set_tail(struct drm_device *dev, 50)) DRM_ERROR("timed out waiting for IDLE Indicator\n"); - I915_WRITE(GEN6_BSD_RING_TAIL, value); + I915_WRITE_TAIL(ring, value); I915_WRITE(GEN6_BSD_SLEEP_PSMI_CONTROL, GEN6_BSD_SLEEP_PSMI_CONTROL_RC_ILDL_MESSAGE_MODIFY_MASK | GEN6_BSD_SLEEP_PSMI_CONTROL_RC_ILDL_MESSAGE_ENABLE); @@ -956,7 +929,6 @@ static const struct intel_ring_buffer gen6_bsd_ring = { .regs = { .ctl = GEN6_BSD_RING_CTL, .head = GEN6_BSD_RING_HEAD, - .tail = GEN6_BSD_RING_TAIL, .start = GEN6_BSD_RING_START }, .mmio_base = GEN6_BSD_RING_BASE, @@ -974,7 +946,6 @@ static const struct intel_ring_buffer gen6_bsd_ring = { .setup_status_page = gen6_bsd_setup_status_page, .init = init_bsd_ring, .get_head = gen6_bsd_ring_get_head, - .get_tail = gen6_bsd_ring_get_tail, .set_tail = gen6_bsd_ring_set_tail, .get_active_head = gen6_bsd_ring_get_active_head, .flush = gen6_bsd_ring_flush, diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.h b/drivers/gpu/drm/i915/intel_ringbuffer.h index 3917d8b..2dfcd9b 100644 --- a/drivers/gpu/drm/i915/intel_ringbuffer.h +++ b/drivers/gpu/drm/i915/intel_ringbuffer.h @@ -7,6 +7,9 @@ struct intel_hw_status_page { struct drm_gem_object *obj; }; +#define I915_READ_TAIL(ring) I915_READ(RING_TAIL(ring->mmio_base)) +#define I915_WRITE_TAIL(ring, val) I915_WRITE(RING_TAIL(ring->mmio_base), val) + struct drm_i915_gem_execbuffer2; struct intel_ring_buffer { const char *name; @@ -17,7 +20,6 @@ struct intel_ring_buffer { struct ring_regs { u32 ctl; u32 head; - u32 tail; u32 start; } regs; u32 mmio_base; @@ -47,10 +49,9 @@ struct intel_ring_buffer { unsigned int (*get_head)(struct drm_device *dev, struct intel_ring_buffer *ring); - unsigned int (*get_tail)(struct drm_device *dev, - struct intel_ring_buffer *ring); void (*set_tail)(struct drm_device *dev, - u32 value); + struct intel_ring_buffer *ring, + u32 value); unsigned int (*get_active_head)(struct drm_device *dev, struct intel_ring_buffer *ring); void (*flush)(struct drm_device *dev, -- cgit v1.1 From 6c0e1c556ee659cd8c976cd175c0b70e209acb92 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Mon, 2 Aug 2010 16:33:33 +0200 Subject: drm/i915: use new macros to access the ring start register Signed-off-by: Daniel Vetter Signed-off-by: Chris Wilson --- drivers/gpu/drm/i915/intel_ringbuffer.c | 11 ++++------- drivers/gpu/drm/i915/intel_ringbuffer.h | 3 ++- 2 files changed, 6 insertions(+), 8 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.c b/drivers/gpu/drm/i915/intel_ringbuffer.c index 4b797e7..395c4d3 100644 --- a/drivers/gpu/drm/i915/intel_ringbuffer.c +++ b/drivers/gpu/drm/i915/intel_ringbuffer.c @@ -157,7 +157,7 @@ static int init_ring_common(struct drm_device *dev, ring->set_tail(dev, ring, 0); /* Initialize the ring. */ - I915_WRITE(ring->regs.start, obj_priv->gtt_offset); + I915_WRITE_START(ring, obj_priv->gtt_offset); head = ring->get_head(dev, ring); /* G45 ring initialization fails to reset head to zero */ @@ -168,7 +168,7 @@ static int init_ring_common(struct drm_device *dev, I915_READ(ring->regs.ctl), I915_READ(ring->regs.head), I915_READ_TAIL(ring), - I915_READ(ring->regs.start)); + I915_READ_START(ring)); I915_WRITE(ring->regs.head, 0); @@ -178,7 +178,7 @@ static int init_ring_common(struct drm_device *dev, I915_READ(ring->regs.ctl), I915_READ(ring->regs.head), I915_READ_TAIL(ring), - I915_READ(ring->regs.start)); + I915_READ_START(ring)); } I915_WRITE(ring->regs.ctl, @@ -194,7 +194,7 @@ static int init_ring_common(struct drm_device *dev, I915_READ(ring->regs.ctl), I915_READ(ring->regs.head), I915_READ_TAIL(ring), - I915_READ(ring->regs.start)); + I915_READ_START(ring)); return -EIO; } @@ -781,7 +781,6 @@ static const struct intel_ring_buffer render_ring = { .regs = { .ctl = PRB0_CTL, .head = PRB0_HEAD, - .start = PRB0_START }, .mmio_base = RENDER_RING_BASE, .size = 32 * PAGE_SIZE, @@ -818,7 +817,6 @@ static const struct intel_ring_buffer bsd_ring = { .regs = { .ctl = BSD_RING_CTL, .head = BSD_RING_HEAD, - .start = BSD_RING_START }, .mmio_base = BSD_RING_BASE, .size = 32 * PAGE_SIZE, @@ -929,7 +927,6 @@ static const struct intel_ring_buffer gen6_bsd_ring = { .regs = { .ctl = GEN6_BSD_RING_CTL, .head = GEN6_BSD_RING_HEAD, - .start = GEN6_BSD_RING_START }, .mmio_base = GEN6_BSD_RING_BASE, .size = 32 * PAGE_SIZE, diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.h b/drivers/gpu/drm/i915/intel_ringbuffer.h index 2dfcd9b..9d0ae5a 100644 --- a/drivers/gpu/drm/i915/intel_ringbuffer.h +++ b/drivers/gpu/drm/i915/intel_ringbuffer.h @@ -9,6 +9,8 @@ struct intel_hw_status_page { #define I915_READ_TAIL(ring) I915_READ(RING_TAIL(ring->mmio_base)) #define I915_WRITE_TAIL(ring, val) I915_WRITE(RING_TAIL(ring->mmio_base), val) +#define I915_READ_START(ring) I915_READ(RING_START(ring->mmio_base)) +#define I915_WRITE_START(ring, val) I915_WRITE(RING_START(ring->mmio_base), val) struct drm_i915_gem_execbuffer2; struct intel_ring_buffer { @@ -20,7 +22,6 @@ struct intel_ring_buffer { struct ring_regs { u32 ctl; u32 head; - u32 start; } regs; u32 mmio_base; unsigned long size; -- cgit v1.1 From 570ef608591aa1c7f7cb615c2d33b30246179da1 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Mon, 2 Aug 2010 17:06:23 +0200 Subject: drm/i915: use new macros to access the ring head register Signed-off-by: Daniel Vetter Signed-off-by: Chris Wilson --- drivers/gpu/drm/i915/intel_ringbuffer.c | 48 ++++++++------------------------- drivers/gpu/drm/i915/intel_ringbuffer.h | 5 ++-- 2 files changed, 13 insertions(+), 40 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.c b/drivers/gpu/drm/i915/intel_ringbuffer.c index 395c4d3..7eb936a 100644 --- a/drivers/gpu/drm/i915/intel_ringbuffer.c +++ b/drivers/gpu/drm/i915/intel_ringbuffer.c @@ -119,13 +119,6 @@ render_ring_flush(struct drm_device *dev, } } -static unsigned int render_ring_get_head(struct drm_device *dev, - struct intel_ring_buffer *ring) -{ - drm_i915_private_t *dev_priv = dev->dev_private; - return I915_READ(PRB0_HEAD) & HEAD_ADDR; -} - static void ring_set_tail(struct drm_device *dev, struct intel_ring_buffer *ring, u32 value) @@ -153,12 +146,12 @@ static int init_ring_common(struct drm_device *dev, /* Stop the ring if it's running. */ I915_WRITE(ring->regs.ctl, 0); - I915_WRITE(ring->regs.head, 0); + I915_WRITE_HEAD(ring, 0); ring->set_tail(dev, ring, 0); /* Initialize the ring. */ I915_WRITE_START(ring, obj_priv->gtt_offset); - head = ring->get_head(dev, ring); + head = I915_READ_HEAD(ring) & HEAD_ADDR; /* G45 ring initialization fails to reset head to zero */ if (head != 0) { @@ -166,17 +159,17 @@ static int init_ring_common(struct drm_device *dev, "ctl %08x head %08x tail %08x start %08x\n", ring->name, I915_READ(ring->regs.ctl), - I915_READ(ring->regs.head), + I915_READ_HEAD(ring), I915_READ_TAIL(ring), I915_READ_START(ring)); - I915_WRITE(ring->regs.head, 0); + I915_WRITE_HEAD(ring, 0); DRM_ERROR("%s head forced to zero " "ctl %08x head %08x tail %08x start %08x\n", ring->name, I915_READ(ring->regs.ctl), - I915_READ(ring->regs.head), + I915_READ_HEAD(ring), I915_READ_TAIL(ring), I915_READ_START(ring)); } @@ -185,14 +178,14 @@ static int init_ring_common(struct drm_device *dev, ((ring->gem_object->size - PAGE_SIZE) & RING_NR_PAGES) | RING_NO_REPORT | RING_VALID); - head = I915_READ(ring->regs.head) & HEAD_ADDR; + head = I915_READ_HEAD(ring) & HEAD_ADDR; /* If the head is still not zero, the ring is dead */ if (head != 0) { DRM_ERROR("%s initialization failed " "ctl %08x head %08x tail %08x start %08x\n", ring->name, I915_READ(ring->regs.ctl), - I915_READ(ring->regs.head), + I915_READ_HEAD(ring), I915_READ_TAIL(ring), I915_READ_START(ring)); return -EIO; @@ -201,7 +194,7 @@ static int init_ring_common(struct drm_device *dev, if (!drm_core_check_feature(dev, DRIVER_MODESET)) i915_kernel_lost_context(dev); else { - ring->head = ring->get_head(dev, ring); + ring->head = I915_READ_HEAD(ring) & HEAD_ADDR; ring->tail = I915_READ_TAIL(ring) & TAIL_ADDR; ring->space = ring->head - (ring->tail + 8); if (ring->space < 0) @@ -381,13 +374,6 @@ bsd_ring_flush(struct drm_device *dev, intel_ring_advance(dev, ring); } -static inline unsigned int bsd_ring_get_head(struct drm_device *dev, - struct intel_ring_buffer *ring) -{ - drm_i915_private_t *dev_priv = dev->dev_private; - return I915_READ(BSD_RING_HEAD) & HEAD_ADDR; -} - static inline unsigned int bsd_ring_get_active_head(struct drm_device *dev, struct intel_ring_buffer *ring) { @@ -650,7 +636,7 @@ int intel_init_ring_buffer(struct drm_device *dev, if (!drm_core_check_feature(dev, DRIVER_MODESET)) i915_kernel_lost_context(dev); else { - ring->head = ring->get_head(dev, ring); + ring->head = I915_READ_HEAD(ring) & HEAD_ADDR; ring->tail = I915_READ_TAIL(ring) & TAIL_ADDR; ring->space = ring->head - (ring->tail + 8); if (ring->space < 0) @@ -716,11 +702,12 @@ int intel_wait_ring_buffer(struct drm_device *dev, struct intel_ring_buffer *ring, int n) { unsigned long end; + drm_i915_private_t *dev_priv = dev->dev_private; trace_i915_ring_wait_begin (dev); end = jiffies + 3 * HZ; do { - ring->head = ring->get_head(dev, ring); + ring->head = I915_READ_HEAD(ring) & HEAD_ADDR; ring->space = ring->head - (ring->tail + 8); if (ring->space < 0) ring->space += ring->size; @@ -780,7 +767,6 @@ static const struct intel_ring_buffer render_ring = { .id = RING_RENDER, .regs = { .ctl = PRB0_CTL, - .head = PRB0_HEAD, }, .mmio_base = RENDER_RING_BASE, .size = 32 * PAGE_SIZE, @@ -796,7 +782,6 @@ static const struct intel_ring_buffer render_ring = { .waiting_gem_seqno = 0, .setup_status_page = render_setup_status_page, .init = init_render_ring, - .get_head = render_ring_get_head, .set_tail = ring_set_tail, .get_active_head = render_ring_get_active_head, .flush = render_ring_flush, @@ -816,7 +801,6 @@ static const struct intel_ring_buffer bsd_ring = { .id = RING_BSD, .regs = { .ctl = BSD_RING_CTL, - .head = BSD_RING_HEAD, }, .mmio_base = BSD_RING_BASE, .size = 32 * PAGE_SIZE, @@ -832,7 +816,6 @@ static const struct intel_ring_buffer bsd_ring = { .waiting_gem_seqno = 0, .setup_status_page = bsd_setup_status_page, .init = init_bsd_ring, - .get_head = bsd_ring_get_head, .set_tail = ring_set_tail, .get_active_head = bsd_ring_get_active_head, .flush = bsd_ring_flush, @@ -854,13 +837,6 @@ static void gen6_bsd_setup_status_page(struct drm_device *dev, I915_READ(GEN6_BSD_HWS_PGA); } -static inline unsigned int gen6_bsd_ring_get_head(struct drm_device *dev, - struct intel_ring_buffer *ring) -{ - drm_i915_private_t *dev_priv = dev->dev_private; - return I915_READ(GEN6_BSD_RING_HEAD) & HEAD_ADDR; -} - static inline void gen6_bsd_ring_set_tail(struct drm_device *dev, struct intel_ring_buffer *ring, u32 value) @@ -926,7 +902,6 @@ static const struct intel_ring_buffer gen6_bsd_ring = { .id = RING_BSD, .regs = { .ctl = GEN6_BSD_RING_CTL, - .head = GEN6_BSD_RING_HEAD, }, .mmio_base = GEN6_BSD_RING_BASE, .size = 32 * PAGE_SIZE, @@ -942,7 +917,6 @@ static const struct intel_ring_buffer gen6_bsd_ring = { .waiting_gem_seqno = 0, .setup_status_page = gen6_bsd_setup_status_page, .init = init_bsd_ring, - .get_head = gen6_bsd_ring_get_head, .set_tail = gen6_bsd_ring_set_tail, .get_active_head = gen6_bsd_ring_get_active_head, .flush = gen6_bsd_ring_flush, diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.h b/drivers/gpu/drm/i915/intel_ringbuffer.h index 9d0ae5a..af09eaa 100644 --- a/drivers/gpu/drm/i915/intel_ringbuffer.h +++ b/drivers/gpu/drm/i915/intel_ringbuffer.h @@ -11,6 +11,8 @@ struct intel_hw_status_page { #define I915_WRITE_TAIL(ring, val) I915_WRITE(RING_TAIL(ring->mmio_base), val) #define I915_READ_START(ring) I915_READ(RING_START(ring->mmio_base)) #define I915_WRITE_START(ring, val) I915_WRITE(RING_START(ring->mmio_base), val) +#define I915_READ_HEAD(ring) I915_READ(RING_HEAD(ring->mmio_base)) +#define I915_WRITE_HEAD(ring, val) I915_WRITE(RING_HEAD(ring->mmio_base), val) struct drm_i915_gem_execbuffer2; struct intel_ring_buffer { @@ -21,7 +23,6 @@ struct intel_ring_buffer { } id; struct ring_regs { u32 ctl; - u32 head; } regs; u32 mmio_base; unsigned long size; @@ -48,8 +49,6 @@ struct intel_ring_buffer { int (*init)(struct drm_device *dev, struct intel_ring_buffer *ring); - unsigned int (*get_head)(struct drm_device *dev, - struct intel_ring_buffer *ring); void (*set_tail)(struct drm_device *dev, struct intel_ring_buffer *ring, u32 value); -- cgit v1.1 From 7f2ab69913135f0377a1dfc1da5695b64107d3ca Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Mon, 2 Aug 2010 17:06:59 +0200 Subject: drm/i915: use new macros to access the ring ctl register Signed-off-by: Daniel Vetter Signed-off-by: Chris Wilson --- drivers/gpu/drm/i915/intel_ringbuffer.c | 19 +++++-------------- drivers/gpu/drm/i915/intel_ringbuffer.h | 5 ++--- 2 files changed, 7 insertions(+), 17 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.c b/drivers/gpu/drm/i915/intel_ringbuffer.c index 7eb936a..1198b60 100644 --- a/drivers/gpu/drm/i915/intel_ringbuffer.c +++ b/drivers/gpu/drm/i915/intel_ringbuffer.c @@ -145,7 +145,7 @@ static int init_ring_common(struct drm_device *dev, obj_priv = to_intel_bo(ring->gem_object); /* Stop the ring if it's running. */ - I915_WRITE(ring->regs.ctl, 0); + I915_WRITE_CTL(ring, 0); I915_WRITE_HEAD(ring, 0); ring->set_tail(dev, ring, 0); @@ -158,7 +158,7 @@ static int init_ring_common(struct drm_device *dev, DRM_ERROR("%s head not reset to zero " "ctl %08x head %08x tail %08x start %08x\n", ring->name, - I915_READ(ring->regs.ctl), + I915_READ_CTL(ring), I915_READ_HEAD(ring), I915_READ_TAIL(ring), I915_READ_START(ring)); @@ -168,13 +168,13 @@ static int init_ring_common(struct drm_device *dev, DRM_ERROR("%s head forced to zero " "ctl %08x head %08x tail %08x start %08x\n", ring->name, - I915_READ(ring->regs.ctl), + I915_READ_CTL(ring), I915_READ_HEAD(ring), I915_READ_TAIL(ring), I915_READ_START(ring)); } - I915_WRITE(ring->regs.ctl, + I915_WRITE_CTL(ring, ((ring->gem_object->size - PAGE_SIZE) & RING_NR_PAGES) | RING_NO_REPORT | RING_VALID); @@ -184,7 +184,7 @@ static int init_ring_common(struct drm_device *dev, DRM_ERROR("%s initialization failed " "ctl %08x head %08x tail %08x start %08x\n", ring->name, - I915_READ(ring->regs.ctl), + I915_READ_CTL(ring), I915_READ_HEAD(ring), I915_READ_TAIL(ring), I915_READ_START(ring)); @@ -765,9 +765,6 @@ void intel_fill_struct(struct drm_device *dev, static const struct intel_ring_buffer render_ring = { .name = "render ring", .id = RING_RENDER, - .regs = { - .ctl = PRB0_CTL, - }, .mmio_base = RENDER_RING_BASE, .size = 32 * PAGE_SIZE, .alignment = PAGE_SIZE, @@ -799,9 +796,6 @@ static const struct intel_ring_buffer render_ring = { static const struct intel_ring_buffer bsd_ring = { .name = "bsd ring", .id = RING_BSD, - .regs = { - .ctl = BSD_RING_CTL, - }, .mmio_base = BSD_RING_BASE, .size = 32 * PAGE_SIZE, .alignment = PAGE_SIZE, @@ -900,9 +894,6 @@ gen6_bsd_ring_dispatch_gem_execbuffer(struct drm_device *dev, static const struct intel_ring_buffer gen6_bsd_ring = { .name = "gen6 bsd ring", .id = RING_BSD, - .regs = { - .ctl = GEN6_BSD_RING_CTL, - }, .mmio_base = GEN6_BSD_RING_BASE, .size = 32 * PAGE_SIZE, .alignment = PAGE_SIZE, diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.h b/drivers/gpu/drm/i915/intel_ringbuffer.h index af09eaa..1668cd9 100644 --- a/drivers/gpu/drm/i915/intel_ringbuffer.h +++ b/drivers/gpu/drm/i915/intel_ringbuffer.h @@ -13,6 +13,8 @@ struct intel_hw_status_page { #define I915_WRITE_START(ring, val) I915_WRITE(RING_START(ring->mmio_base), val) #define I915_READ_HEAD(ring) I915_READ(RING_HEAD(ring->mmio_base)) #define I915_WRITE_HEAD(ring, val) I915_WRITE(RING_HEAD(ring->mmio_base), val) +#define I915_READ_CTL(ring) I915_READ(RING_CTL(ring->mmio_base)) +#define I915_WRITE_CTL(ring, val) I915_WRITE(RING_CTL(ring->mmio_base), val) struct drm_i915_gem_execbuffer2; struct intel_ring_buffer { @@ -21,9 +23,6 @@ struct intel_ring_buffer { RING_RENDER = 0x1, RING_BSD = 0x2, } id; - struct ring_regs { - u32 ctl; - } regs; u32 mmio_base; unsigned long size; unsigned int alignment; -- cgit v1.1 From fa7ed4d206890fd325eddcc8d27d6d1e89c5d4bd Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Mon, 2 Aug 2010 17:08:41 +0200 Subject: drm/i915: don't explicitly initialize ringbuffer members to zero The compiler happily does that for us. Signed-off-by: Daniel Vetter Signed-off-by: Chris Wilson --- drivers/gpu/drm/i915/intel_ringbuffer.c | 33 --------------------------------- 1 file changed, 33 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.c b/drivers/gpu/drm/i915/intel_ringbuffer.c index 1198b60..d395d05 100644 --- a/drivers/gpu/drm/i915/intel_ringbuffer.c +++ b/drivers/gpu/drm/i915/intel_ringbuffer.c @@ -768,15 +768,6 @@ static const struct intel_ring_buffer render_ring = { .mmio_base = RENDER_RING_BASE, .size = 32 * PAGE_SIZE, .alignment = PAGE_SIZE, - .virtual_start = NULL, - .dev = NULL, - .gem_object = NULL, - .head = 0, - .tail = 0, - .space = 0, - .user_irq_refcount = 0, - .irq_gem_seqno = 0, - .waiting_gem_seqno = 0, .setup_status_page = render_setup_status_page, .init = init_render_ring, .set_tail = ring_set_tail, @@ -787,8 +778,6 @@ static const struct intel_ring_buffer render_ring = { .user_irq_get = render_ring_get_user_irq, .user_irq_put = render_ring_put_user_irq, .dispatch_gem_execbuffer = render_ring_dispatch_gem_execbuffer, - .status_page = {NULL, 0, NULL}, - .map = {0,} }; /* ring buffer for bit-stream decoder */ @@ -799,15 +788,6 @@ static const struct intel_ring_buffer bsd_ring = { .mmio_base = BSD_RING_BASE, .size = 32 * PAGE_SIZE, .alignment = PAGE_SIZE, - .virtual_start = NULL, - .dev = NULL, - .gem_object = NULL, - .head = 0, - .tail = 0, - .space = 0, - .user_irq_refcount = 0, - .irq_gem_seqno = 0, - .waiting_gem_seqno = 0, .setup_status_page = bsd_setup_status_page, .init = init_bsd_ring, .set_tail = ring_set_tail, @@ -818,8 +798,6 @@ static const struct intel_ring_buffer bsd_ring = { .user_irq_get = bsd_ring_get_user_irq, .user_irq_put = bsd_ring_put_user_irq, .dispatch_gem_execbuffer = bsd_ring_dispatch_gem_execbuffer, - .status_page = {NULL, 0, NULL}, - .map = {0,} }; @@ -897,15 +875,6 @@ static const struct intel_ring_buffer gen6_bsd_ring = { .mmio_base = GEN6_BSD_RING_BASE, .size = 32 * PAGE_SIZE, .alignment = PAGE_SIZE, - .virtual_start = NULL, - .dev = NULL, - .gem_object = NULL, - .head = 0, - .tail = 0, - .space = 0, - .user_irq_refcount = 0, - .irq_gem_seqno = 0, - .waiting_gem_seqno = 0, .setup_status_page = gen6_bsd_setup_status_page, .init = init_bsd_ring, .set_tail = gen6_bsd_ring_set_tail, @@ -916,8 +885,6 @@ static const struct intel_ring_buffer gen6_bsd_ring = { .user_irq_get = bsd_ring_get_user_irq, .user_irq_put = bsd_ring_put_user_irq, .dispatch_gem_execbuffer = gen6_bsd_ring_dispatch_gem_execbuffer, - .status_page = {NULL, 0, NULL}, - .map = {0,} }; int intel_init_render_ring_buffer(struct drm_device *dev) -- cgit v1.1 From a9db5c8fdd8c6e6e966897e05e2c2acd99bcdb6e Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Mon, 2 Aug 2010 17:22:48 +0200 Subject: drm/i915: drop alignment ringbuffer parameter Always PAGE_SIZE and only complicates the code. Signed-off-by: Daniel Vetter Signed-off-by: Chris Wilson --- drivers/gpu/drm/i915/intel_ringbuffer.c | 5 +---- drivers/gpu/drm/i915/intel_ringbuffer.h | 1 - 2 files changed, 1 insertion(+), 5 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.c b/drivers/gpu/drm/i915/intel_ringbuffer.c index d395d05..c9894c2 100644 --- a/drivers/gpu/drm/i915/intel_ringbuffer.c +++ b/drivers/gpu/drm/i915/intel_ringbuffer.c @@ -610,7 +610,7 @@ int intel_init_ring_buffer(struct drm_device *dev, ring->gem_object = obj; - ret = i915_gem_object_pin(obj, ring->alignment); + ret = i915_gem_object_pin(obj, PAGE_SIZE); if (ret) goto err_unref; @@ -767,7 +767,6 @@ static const struct intel_ring_buffer render_ring = { .id = RING_RENDER, .mmio_base = RENDER_RING_BASE, .size = 32 * PAGE_SIZE, - .alignment = PAGE_SIZE, .setup_status_page = render_setup_status_page, .init = init_render_ring, .set_tail = ring_set_tail, @@ -787,7 +786,6 @@ static const struct intel_ring_buffer bsd_ring = { .id = RING_BSD, .mmio_base = BSD_RING_BASE, .size = 32 * PAGE_SIZE, - .alignment = PAGE_SIZE, .setup_status_page = bsd_setup_status_page, .init = init_bsd_ring, .set_tail = ring_set_tail, @@ -874,7 +872,6 @@ static const struct intel_ring_buffer gen6_bsd_ring = { .id = RING_BSD, .mmio_base = GEN6_BSD_RING_BASE, .size = 32 * PAGE_SIZE, - .alignment = PAGE_SIZE, .setup_status_page = gen6_bsd_setup_status_page, .init = init_bsd_ring, .set_tail = gen6_bsd_ring_set_tail, diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.h b/drivers/gpu/drm/i915/intel_ringbuffer.h index 1668cd9..abf8a4e 100644 --- a/drivers/gpu/drm/i915/intel_ringbuffer.h +++ b/drivers/gpu/drm/i915/intel_ringbuffer.h @@ -25,7 +25,6 @@ struct intel_ring_buffer { } id; u32 mmio_base; unsigned long size; - unsigned int alignment; void *virtual_start; struct drm_device *dev; struct drm_gem_object *gem_object; -- cgit v1.1 From ab6f8e325083f138ce5da8417baf48887d62da3c Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Sun, 19 Sep 2010 17:53:44 +0100 Subject: drm/i915/ringbuffer: whitespace cleanup Signed-off-by: Chris Wilson --- drivers/gpu/drm/i915/intel_ringbuffer.c | 123 +++++++++++++++++--------------- drivers/gpu/drm/i915/intel_ringbuffer.h | 10 ++- 2 files changed, 68 insertions(+), 65 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.c b/drivers/gpu/drm/i915/intel_ringbuffer.c index c9894c2..1bcea7c 100644 --- a/drivers/gpu/drm/i915/intel_ringbuffer.c +++ b/drivers/gpu/drm/i915/intel_ringbuffer.c @@ -50,9 +50,9 @@ static u32 i915_gem_get_seqno(struct drm_device *dev) static void render_ring_flush(struct drm_device *dev, - struct intel_ring_buffer *ring, - u32 invalidate_domains, - u32 flush_domains) + struct intel_ring_buffer *ring, + u32 invalidate_domains, + u32 flush_domains) { drm_i915_private_t *dev_priv = dev->dev_private; u32 cmd; @@ -128,7 +128,7 @@ static void ring_set_tail(struct drm_device *dev, } static unsigned int render_ring_get_active_head(struct drm_device *dev, - struct intel_ring_buffer *ring) + struct intel_ring_buffer *ring) { drm_i915_private_t *dev_priv = dev->dev_private; u32 acthd_reg = INTEL_INFO(dev)->gen ? ACTHD_I965 : ACTHD; @@ -137,7 +137,7 @@ static unsigned int render_ring_get_active_head(struct drm_device *dev, } static int init_ring_common(struct drm_device *dev, - struct intel_ring_buffer *ring) + struct intel_ring_buffer *ring) { u32 head; drm_i915_private_t *dev_priv = dev->dev_private; @@ -204,7 +204,7 @@ static int init_ring_common(struct drm_device *dev, } static int init_render_ring(struct drm_device *dev, - struct intel_ring_buffer *ring) + struct intel_ring_buffer *ring) { drm_i915_private_t *dev_priv = dev->dev_private; int ret = init_ring_common(dev, ring); @@ -238,9 +238,9 @@ do { \ */ static u32 render_ring_add_request(struct drm_device *dev, - struct intel_ring_buffer *ring, - struct drm_file *file_priv, - u32 flush_domains) + struct intel_ring_buffer *ring, + struct drm_file *file_priv, + u32 flush_domains) { drm_i915_private_t *dev_priv = dev->dev_private; u32 seqno; @@ -304,7 +304,7 @@ render_ring_add_request(struct drm_device *dev, static u32 render_ring_get_gem_seqno(struct drm_device *dev, - struct intel_ring_buffer *ring) + struct intel_ring_buffer *ring) { drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; if (HAS_PIPE_CONTROL(dev)) @@ -315,7 +315,7 @@ render_ring_get_gem_seqno(struct drm_device *dev, static void render_ring_get_user_irq(struct drm_device *dev, - struct intel_ring_buffer *ring) + struct intel_ring_buffer *ring) { drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; unsigned long irqflags; @@ -332,7 +332,7 @@ render_ring_get_user_irq(struct drm_device *dev, static void render_ring_put_user_irq(struct drm_device *dev, - struct intel_ring_buffer *ring) + struct intel_ring_buffer *ring) { drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; unsigned long irqflags; @@ -349,7 +349,7 @@ render_ring_put_user_irq(struct drm_device *dev, } static void render_setup_status_page(struct drm_device *dev, - struct intel_ring_buffer *ring) + struct intel_ring_buffer *ring) { drm_i915_private_t *dev_priv = dev->dev_private; if (IS_GEN6(dev)) { @@ -362,7 +362,7 @@ static void render_setup_status_page(struct drm_device *dev, } -void +static void bsd_ring_flush(struct drm_device *dev, struct intel_ring_buffer *ring, u32 invalidate_domains, @@ -374,24 +374,24 @@ bsd_ring_flush(struct drm_device *dev, intel_ring_advance(dev, ring); } -static inline unsigned int bsd_ring_get_active_head(struct drm_device *dev, - struct intel_ring_buffer *ring) +static unsigned int bsd_ring_get_active_head(struct drm_device *dev, + struct intel_ring_buffer *ring) { drm_i915_private_t *dev_priv = dev->dev_private; return I915_READ(BSD_RING_ACTHD); } static int init_bsd_ring(struct drm_device *dev, - struct intel_ring_buffer *ring) + struct intel_ring_buffer *ring) { return init_ring_common(dev, ring); } static u32 bsd_ring_add_request(struct drm_device *dev, - struct intel_ring_buffer *ring, - struct drm_file *file_priv, - u32 flush_domains) + struct intel_ring_buffer *ring, + struct drm_file *file_priv, + u32 flush_domains) { u32 seqno; @@ -411,7 +411,7 @@ bsd_ring_add_request(struct drm_device *dev, } static void bsd_setup_status_page(struct drm_device *dev, - struct intel_ring_buffer *ring) + struct intel_ring_buffer *ring) { drm_i915_private_t *dev_priv = dev->dev_private; I915_WRITE(BSD_HWS_PGA, ring->status_page.gfx_addr); @@ -420,30 +420,30 @@ static void bsd_setup_status_page(struct drm_device *dev, static void bsd_ring_get_user_irq(struct drm_device *dev, - struct intel_ring_buffer *ring) + struct intel_ring_buffer *ring) { /* do nothing */ } static void bsd_ring_put_user_irq(struct drm_device *dev, - struct intel_ring_buffer *ring) + struct intel_ring_buffer *ring) { /* do nothing */ } static u32 bsd_ring_get_gem_seqno(struct drm_device *dev, - struct intel_ring_buffer *ring) + struct intel_ring_buffer *ring) { return intel_read_status_page(ring, I915_GEM_HWS_INDEX); } static int bsd_ring_dispatch_gem_execbuffer(struct drm_device *dev, - struct intel_ring_buffer *ring, - struct drm_i915_gem_execbuffer2 *exec, - struct drm_clip_rect *cliprects, - uint64_t exec_offset) + struct intel_ring_buffer *ring, + struct drm_i915_gem_execbuffer2 *exec, + struct drm_clip_rect *cliprects, + uint64_t exec_offset) { uint32_t exec_start; exec_start = (uint32_t) exec_offset + exec->batch_start_offset; @@ -458,10 +458,10 @@ bsd_ring_dispatch_gem_execbuffer(struct drm_device *dev, static int render_ring_dispatch_gem_execbuffer(struct drm_device *dev, - struct intel_ring_buffer *ring, - struct drm_i915_gem_execbuffer2 *exec, - struct drm_clip_rect *cliprects, - uint64_t exec_offset) + struct intel_ring_buffer *ring, + struct drm_i915_gem_execbuffer2 *exec, + struct drm_clip_rect *cliprects, + uint64_t exec_offset) { drm_i915_private_t *dev_priv = dev->dev_private; int nbox = exec->num_cliprects; @@ -520,7 +520,7 @@ render_ring_dispatch_gem_execbuffer(struct drm_device *dev, } static void cleanup_status_page(struct drm_device *dev, - struct intel_ring_buffer *ring) + struct intel_ring_buffer *ring) { drm_i915_private_t *dev_priv = dev->dev_private; struct drm_gem_object *obj; @@ -540,7 +540,7 @@ static void cleanup_status_page(struct drm_device *dev, } static int init_status_page(struct drm_device *dev, - struct intel_ring_buffer *ring) + struct intel_ring_buffer *ring) { drm_i915_private_t *dev_priv = dev->dev_private; struct drm_gem_object *obj; @@ -584,9 +584,8 @@ err: return ret; } - int intel_init_ring_buffer(struct drm_device *dev, - struct intel_ring_buffer *ring) + struct intel_ring_buffer *ring) { struct drm_i915_private *dev_priv = dev->dev_private; struct drm_i915_gem_object *obj_priv; @@ -659,7 +658,7 @@ err_hws: } void intel_cleanup_ring_buffer(struct drm_device *dev, - struct intel_ring_buffer *ring) + struct intel_ring_buffer *ring) { if (ring->gem_object == NULL) return; @@ -672,8 +671,8 @@ void intel_cleanup_ring_buffer(struct drm_device *dev, cleanup_status_page(dev, ring); } -int intel_wrap_ring_buffer(struct drm_device *dev, - struct intel_ring_buffer *ring) +static int intel_wrap_ring_buffer(struct drm_device *dev, + struct intel_ring_buffer *ring) { unsigned int *virt; int rem; @@ -699,7 +698,7 @@ int intel_wrap_ring_buffer(struct drm_device *dev, } int intel_wait_ring_buffer(struct drm_device *dev, - struct intel_ring_buffer *ring, int n) + struct intel_ring_buffer *ring, int n) { unsigned long end; drm_i915_private_t *dev_priv = dev->dev_private; @@ -729,7 +728,8 @@ int intel_wait_ring_buffer(struct drm_device *dev, } void intel_ring_begin(struct drm_device *dev, - struct intel_ring_buffer *ring, int num_dwords) + struct intel_ring_buffer *ring, + int num_dwords) { int n = 4*num_dwords; if (unlikely(ring->tail + n > ring->size)) @@ -741,16 +741,16 @@ void intel_ring_begin(struct drm_device *dev, } void intel_ring_advance(struct drm_device *dev, - struct intel_ring_buffer *ring) + struct intel_ring_buffer *ring) { ring->tail &= ring->size - 1; ring->set_tail(dev, ring, ring->tail); } void intel_fill_struct(struct drm_device *dev, - struct intel_ring_buffer *ring, - void *data, - unsigned int len) + struct intel_ring_buffer *ring, + void *data, + unsigned int len) { unsigned int *virt = ring->virtual_start + ring->tail; BUG_ON((len&~(4-1)) != 0); @@ -800,16 +800,16 @@ static const struct intel_ring_buffer bsd_ring = { static void gen6_bsd_setup_status_page(struct drm_device *dev, - struct intel_ring_buffer *ring) + struct intel_ring_buffer *ring) { drm_i915_private_t *dev_priv = dev->dev_private; I915_WRITE(GEN6_BSD_HWS_PGA, ring->status_page.gfx_addr); I915_READ(GEN6_BSD_HWS_PGA); } -static inline void gen6_bsd_ring_set_tail(struct drm_device *dev, - struct intel_ring_buffer *ring, - u32 value) +static void gen6_bsd_ring_set_tail(struct drm_device *dev, + struct intel_ring_buffer *ring, + u32 value) { drm_i915_private_t *dev_priv = dev->dev_private; @@ -830,17 +830,17 @@ static inline void gen6_bsd_ring_set_tail(struct drm_device *dev, GEN6_BSD_SLEEP_PSMI_CONTROL_RC_ILDL_MESSAGE_ENABLE); } -static inline unsigned int gen6_bsd_ring_get_active_head(struct drm_device *dev, - struct intel_ring_buffer *ring) +static unsigned int gen6_bsd_ring_get_active_head(struct drm_device *dev, + struct intel_ring_buffer *ring) { drm_i915_private_t *dev_priv = dev->dev_private; return I915_READ(GEN6_BSD_RING_ACTHD); } static void gen6_bsd_ring_flush(struct drm_device *dev, - struct intel_ring_buffer *ring, - u32 invalidate_domains, - u32 flush_domains) + struct intel_ring_buffer *ring, + u32 invalidate_domains, + u32 flush_domains) { intel_ring_begin(dev, ring, 4); intel_ring_emit(dev, ring, MI_FLUSH_DW); @@ -852,17 +852,22 @@ static void gen6_bsd_ring_flush(struct drm_device *dev, static int gen6_bsd_ring_dispatch_gem_execbuffer(struct drm_device *dev, - struct intel_ring_buffer *ring, - struct drm_i915_gem_execbuffer2 *exec, - struct drm_clip_rect *cliprects, - uint64_t exec_offset) + struct intel_ring_buffer *ring, + struct drm_i915_gem_execbuffer2 *exec, + struct drm_clip_rect *cliprects, + uint64_t exec_offset) { uint32_t exec_start; + exec_start = (uint32_t) exec_offset + exec->batch_start_offset; + intel_ring_begin(dev, ring, 2); - intel_ring_emit(dev, ring, MI_BATCH_BUFFER_START | MI_BATCH_NON_SECURE_I965); /* bit0-7 is the length on GEN6+ */ + intel_ring_emit(dev, ring, + MI_BATCH_BUFFER_START | MI_BATCH_NON_SECURE_I965); + /* bit0-7 is the length on GEN6+ */ intel_ring_emit(dev, ring, exec_start); intel_ring_advance(dev, ring); + return 0; } diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.h b/drivers/gpu/drm/i915/intel_ringbuffer.h index abf8a4e..2d3165f 100644 --- a/drivers/gpu/drm/i915/intel_ringbuffer.h +++ b/drivers/gpu/drm/i915/intel_ringbuffer.h @@ -104,15 +104,13 @@ intel_read_status_page(struct intel_ring_buffer *ring, } int intel_init_ring_buffer(struct drm_device *dev, - struct intel_ring_buffer *ring); + struct intel_ring_buffer *ring); void intel_cleanup_ring_buffer(struct drm_device *dev, - struct intel_ring_buffer *ring); + struct intel_ring_buffer *ring); int intel_wait_ring_buffer(struct drm_device *dev, - struct intel_ring_buffer *ring, int n); -int intel_wrap_ring_buffer(struct drm_device *dev, - struct intel_ring_buffer *ring); + struct intel_ring_buffer *ring, int n); void intel_ring_begin(struct drm_device *dev, - struct intel_ring_buffer *ring, int n); + struct intel_ring_buffer *ring, int n); static inline void intel_ring_emit(struct drm_device *dev, struct intel_ring_buffer *ring, -- cgit v1.1 From 53640e1d07fb7dd5d14300dd94f4718eca33348e Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Mon, 20 Sep 2010 11:40:50 +0100 Subject: drm/i915: Track gpu fence usage Track if the gpu requires the fence for the execution of a batch buffer and so only wait upon the retirement of the object's last rendering seqno if the fence is in use by the GPU. Signed-off-by: Chris Wilson --- drivers/gpu/drm/i915/i915_drv.h | 1 + drivers/gpu/drm/i915/i915_gem.c | 11 +++++++++-- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 790ffec..6e22be4 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -128,6 +128,7 @@ struct drm_i915_master_private { struct drm_i915_fence_reg { struct drm_gem_object *obj; struct list_head lru_list; + bool gpu; }; struct sdvo_device_mapping { diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index b242530..a5d5751 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -2461,7 +2461,9 @@ i915_gem_object_put_fence_reg(struct drm_gem_object *obj, bool interruptible) { struct drm_device *dev = obj->dev; + struct drm_i915_private *dev_priv = dev->dev_private; struct drm_i915_gem_object *obj_priv = to_intel_bo(obj); + struct drm_i915_fence_reg *reg; if (obj_priv->fence_reg == I915_FENCE_REG_NONE) return 0; @@ -2476,7 +2478,8 @@ i915_gem_object_put_fence_reg(struct drm_gem_object *obj, * therefore we must wait for any outstanding access to complete * before clearing the fence. */ - if (INTEL_INFO(dev)->gen < 4) { + reg = &dev_priv->fence_regs[obj_priv->fence_reg]; + if (reg->gpu) { int ret; ret = i915_gem_object_flush_gpu_write_domain(obj, true); @@ -2486,6 +2489,8 @@ i915_gem_object_put_fence_reg(struct drm_gem_object *obj, ret = i915_gem_object_wait_rendering(obj, interruptible); if (ret) return ret; + + reg->gpu = false; } i915_gem_object_flush_gtt_write_domain(obj); @@ -3180,11 +3185,13 @@ i915_gem_object_pin_and_relocate(struct drm_gem_object *obj, * properly handle blits to/from tiled surfaces. */ if (need_fence) { - ret = i915_gem_object_get_fence_reg(obj, false); + ret = i915_gem_object_get_fence_reg(obj, true); if (ret != 0) { i915_gem_object_unpin(obj); return ret; } + + dev_priv->fence_regs[obj_priv->fence_reg].gpu = true; } entry->offset = obj_priv->gtt_offset; -- cgit v1.1 From c78ec30bba52754b9f21a899eac2e2f5a7486116 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Mon, 20 Sep 2010 12:50:23 +0100 Subject: drm/i915: Merge ring flushing and lazy requests Signed-off-by: Chris Wilson --- drivers/gpu/drm/i915/i915_drv.h | 1 + drivers/gpu/drm/i915/i915_gem.c | 53 +++++++++++++++--------------------- drivers/gpu/drm/i915/intel_display.c | 2 +- 3 files changed, 24 insertions(+), 32 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 6e22be4..37a44c8 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -1003,6 +1003,7 @@ void i915_gem_reset_flushing_list(struct drm_device *dev); void i915_gem_reset_inactive_gpu_domains(struct drm_device *dev); void i915_gem_clflush_object(struct drm_gem_object *obj); void i915_gem_flush_ring(struct drm_device *dev, + struct drm_file *file_priv, struct intel_ring_buffer *ring, uint32_t invalidate_domains, uint32_t flush_domains); diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index a5d5751..58baecc 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -1910,16 +1910,23 @@ i915_wait_request(struct drm_device *dev, uint32_t seqno, void i915_gem_flush_ring(struct drm_device *dev, + struct drm_file *file_priv, struct intel_ring_buffer *ring, uint32_t invalidate_domains, uint32_t flush_domains) { ring->flush(dev, ring, invalidate_domains, flush_domains); i915_gem_process_flushing_list(dev, flush_domains, ring); + + if (ring->outstanding_lazy_request) { + (void)i915_add_request(dev, file_priv, NULL, ring); + ring->outstanding_lazy_request = false; + } } static void i915_gem_flush(struct drm_device *dev, + struct drm_file *file_priv, uint32_t invalidate_domains, uint32_t flush_domains, uint32_t flush_rings) @@ -1931,11 +1938,11 @@ i915_gem_flush(struct drm_device *dev, if ((flush_domains | invalidate_domains) & I915_GEM_GPU_DOMAINS) { if (flush_rings & RING_RENDER) - i915_gem_flush_ring(dev, + i915_gem_flush_ring(dev, file_priv, &dev_priv->render_ring, invalidate_domains, flush_domains); if (flush_rings & RING_BSD) - i915_gem_flush_ring(dev, + i915_gem_flush_ring(dev, file_priv, &dev_priv->bsd_ring, invalidate_domains, flush_domains); } @@ -2054,6 +2061,7 @@ i915_gpu_idle(struct drm_device *dev) { drm_i915_private_t *dev_priv = dev->dev_private; bool lists_empty; + u32 seqno; int ret; lists_empty = (list_empty(&dev_priv->mm.flushing_list) && @@ -2064,24 +2072,18 @@ i915_gpu_idle(struct drm_device *dev) return 0; /* Flush everything onto the inactive list. */ - i915_gem_flush_ring(dev, - &dev_priv->render_ring, + seqno = i915_gem_next_request_seqno(dev, &dev_priv->render_ring); + i915_gem_flush_ring(dev, NULL, &dev_priv->render_ring, I915_GEM_GPU_DOMAINS, I915_GEM_GPU_DOMAINS); - - ret = i915_wait_request(dev, - i915_gem_next_request_seqno(dev, &dev_priv->render_ring), - &dev_priv->render_ring); + ret = i915_wait_request(dev, seqno, &dev_priv->render_ring); if (ret) return ret; if (HAS_BSD(dev)) { - i915_gem_flush_ring(dev, - &dev_priv->bsd_ring, + seqno = i915_gem_next_request_seqno(dev, &dev_priv->render_ring); + i915_gem_flush_ring(dev, NULL, &dev_priv->bsd_ring, I915_GEM_GPU_DOMAINS, I915_GEM_GPU_DOMAINS); - - ret = i915_wait_request(dev, - i915_gem_next_request_seqno(dev, &dev_priv->bsd_ring), - &dev_priv->bsd_ring); + ret = i915_wait_request(dev, seqno, &dev_priv->bsd_ring); if (ret) return ret; } @@ -2651,7 +2653,7 @@ i915_gem_object_flush_gpu_write_domain(struct drm_gem_object *obj, /* Queue the GPU write cache flushing we need. */ old_write_domain = obj->write_domain; - i915_gem_flush_ring(dev, + i915_gem_flush_ring(dev, NULL, to_intel_bo(obj)->ring, 0, obj->write_domain); BUG_ON(obj->write_domain); @@ -2780,7 +2782,7 @@ i915_gem_object_set_to_display_plane(struct drm_gem_object *obj, i915_gem_object_flush_cpu_write_domain(obj); old_read_domains = obj->read_domains; - obj->read_domains = I915_GEM_DOMAIN_GTT; + obj->read_domains |= I915_GEM_DOMAIN_GTT; trace_i915_gem_object_change_domain(obj, old_read_domains, @@ -2837,7 +2839,7 @@ i915_gem_object_set_to_cpu_domain(struct drm_gem_object *obj, int write) * need to be invalidated at next use. */ if (write) { - obj->read_domains &= I915_GEM_DOMAIN_CPU; + obj->read_domains = I915_GEM_DOMAIN_CPU; obj->write_domain = I915_GEM_DOMAIN_CPU; } @@ -3762,21 +3764,12 @@ i915_gem_do_execbuffer(struct drm_device *dev, void *data, dev->invalidate_domains, dev->flush_domains); #endif - i915_gem_flush(dev, + i915_gem_flush(dev, file_priv, dev->invalidate_domains, dev->flush_domains, dev_priv->mm.flush_rings); } - if (dev_priv->render_ring.outstanding_lazy_request) { - (void)i915_add_request(dev, file_priv, NULL, &dev_priv->render_ring); - dev_priv->render_ring.outstanding_lazy_request = false; - } - if (dev_priv->bsd_ring.outstanding_lazy_request) { - (void)i915_add_request(dev, file_priv, NULL, &dev_priv->bsd_ring); - dev_priv->bsd_ring.outstanding_lazy_request = false; - } - for (i = 0; i < args->buffer_count; i++) { struct drm_gem_object *obj = object_list[i]; struct drm_i915_gem_object *obj_priv = to_intel_bo(obj); @@ -4232,12 +4225,10 @@ i915_gem_busy_ioctl(struct drm_device *dev, void *data, * use this buffer rather sooner than later, so issuing the required * flush earlier is beneficial. */ - if (obj->write_domain & I915_GEM_GPU_DOMAINS) { - i915_gem_flush_ring(dev, + if (obj->write_domain & I915_GEM_GPU_DOMAINS) + i915_gem_flush_ring(dev, file_priv, obj_priv->ring, 0, obj->write_domain); - (void)i915_add_request(dev, file_priv, NULL, obj_priv->ring); - } /* Update the active list for the hardware's current position. * Otherwise this only updates on a delayed timer or when irqs diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 0505ddb..791374c 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -5058,7 +5058,7 @@ static int intel_crtc_page_flip(struct drm_crtc *crtc, /* Schedule the pipelined flush */ if (was_dirty) - i915_gem_flush_ring(dev, obj_priv->ring, 0, was_dirty); + i915_gem_flush_ring(dev, NULL, obj_priv->ring, 0, was_dirty); if (IS_GEN3(dev) || IS_GEN2(dev)) { u32 flip_mask; -- cgit v1.1 From 265db9585e570814d2f7aca109c5563bcde9c948 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Mon, 20 Sep 2010 15:41:01 +0100 Subject: drm/i915: Drain any pending flips on the fb prior to unpinning If we have queued a page flip on the current fb and then request a mode change, wait until the page flip completes before performing the new request. Signed-off-by: Chris Wilson --- drivers/gpu/drm/i915/i915_drv.h | 3 +++ drivers/gpu/drm/i915/i915_gem.c | 2 +- drivers/gpu/drm/i915/intel_display.c | 41 +++++++++++++++++++----------------- 3 files changed, 26 insertions(+), 20 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 37a44c8..ce8ff8f 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -1024,6 +1024,9 @@ int i915_do_wait_request(struct drm_device *dev, uint32_t seqno, bool interruptible, struct intel_ring_buffer *ring); +int i915_gem_wait_for_pending_flip(struct drm_device *dev, + struct drm_gem_object **object_list, + int count); int i915_gem_fault(struct vm_area_struct *vma, struct vm_fault *vmf); int i915_gem_object_set_to_gtt_domain(struct drm_gem_object *obj, int write); diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index 58baecc..a8ddcd4 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -3497,7 +3497,7 @@ i915_gem_check_execbuffer (struct drm_i915_gem_execbuffer2 *exec, return 0; } -static int +int i915_gem_wait_for_pending_flip(struct drm_device *dev, struct drm_gem_object **object_list, int count) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 791374c..461bf48 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -1564,11 +1564,6 @@ intel_pipe_set_base(struct drm_crtc *crtc, int x, int y, struct drm_device *dev = crtc->dev; struct drm_i915_master_private *master_priv; struct intel_crtc *intel_crtc = to_intel_crtc(crtc); - struct intel_framebuffer *intel_fb; - struct drm_i915_gem_object *obj_priv; - struct drm_gem_object *obj; - int pipe = intel_crtc->pipe; - int plane = intel_crtc->plane; int ret; /* no fb bound */ @@ -1577,38 +1572,46 @@ intel_pipe_set_base(struct drm_crtc *crtc, int x, int y, return 0; } - switch (plane) { + switch (intel_crtc->plane) { case 0: case 1: break; default: - DRM_ERROR("Can't update plane %d in SAREA\n", plane); return -EINVAL; } - intel_fb = to_intel_framebuffer(crtc->fb); - obj = intel_fb->obj; - obj_priv = to_intel_bo(obj); - mutex_lock(&dev->struct_mutex); - ret = intel_pin_and_fence_fb_obj(dev, obj, false); + ret = intel_pin_and_fence_fb_obj(dev, + to_intel_framebuffer(crtc->fb)->obj, + false); if (ret != 0) { mutex_unlock(&dev->struct_mutex); return ret; } + if (old_fb) { + struct drm_gem_object *obj = to_intel_framebuffer(old_fb)->obj; + struct drm_i915_gem_object *obj_priv = to_intel_bo(obj); + + if (atomic_read(&obj_priv->pending_flip)) { + ret = i915_gem_wait_for_pending_flip(dev, &obj, 1); + if (ret) { + i915_gem_object_unpin(to_intel_framebuffer(crtc->fb)->obj); + mutex_unlock(&dev->struct_mutex); + return ret; + } + } + } + ret = intel_pipe_set_base_atomic(crtc, crtc->fb, x, y); if (ret) { - i915_gem_object_unpin(obj); + i915_gem_object_unpin(to_intel_framebuffer(crtc->fb)->obj); mutex_unlock(&dev->struct_mutex); return ret; } - if (old_fb) { - intel_fb = to_intel_framebuffer(old_fb); - obj_priv = to_intel_bo(intel_fb->obj); - i915_gem_object_unpin(intel_fb->obj); - } + if (old_fb) + i915_gem_object_unpin(to_intel_framebuffer(old_fb)->obj); mutex_unlock(&dev->struct_mutex); @@ -1619,7 +1622,7 @@ intel_pipe_set_base(struct drm_crtc *crtc, int x, int y, if (!master_priv->sarea_priv) return 0; - if (pipe) { + if (intel_crtc->pipe) { master_priv->sarea_priv->pipeB_x = x; master_priv->sarea_priv->pipeB_y = y; } else { -- cgit v1.1 From f13d3f7311add99d1f874a6b67d56426afa35664 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Mon, 20 Sep 2010 17:36:15 +0100 Subject: drm/i915: Track pinned objects Keep a list of pinned objects and display it via debugfs. Now all objects that exist in the GTT are always tracked on one of the active, flushing, inactive or pinned lists. Signed-off-by: Chris Wilson --- drivers/gpu/drm/i915/i915_debugfs.c | 16 ++++++++++++---- drivers/gpu/drm/i915/i915_drv.h | 6 ++++++ drivers/gpu/drm/i915/i915_gem.c | 18 ++++++++---------- 3 files changed, 26 insertions(+), 14 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_debugfs.c b/drivers/gpu/drm/i915/i915_debugfs.c index ac48115..36f0e36 100644 --- a/drivers/gpu/drm/i915/i915_debugfs.c +++ b/drivers/gpu/drm/i915/i915_debugfs.c @@ -40,10 +40,13 @@ #if defined(CONFIG_DEBUG_FS) -#define RENDER_LIST 1 -#define BSD_LIST 2 -#define FLUSHING_LIST 3 -#define INACTIVE_LIST 4 +enum { + RENDER_LIST, + BSD_LIST, + FLUSHING_LIST, + INACTIVE_LIST, + PINNED_LIST +}; static const char *yesno(int v) { @@ -150,6 +153,10 @@ static int i915_gem_object_list_info(struct seq_file *m, void *data) seq_printf(m, "Inactive:\n"); head = &dev_priv->mm.inactive_list; break; + case PINNED_LIST: + seq_printf(m, "Pinned:\n"); + head = &dev_priv->mm.pinned_list; + break; case FLUSHING_LIST: seq_printf(m, "Flushing:\n"); head = &dev_priv->mm.flushing_list; @@ -983,6 +990,7 @@ static struct drm_info_list i915_debugfs_list[] = { {"i915_gem_bsd_active", i915_gem_object_list_info, 0, (void *) BSD_LIST}, {"i915_gem_flushing", i915_gem_object_list_info, 0, (void *) FLUSHING_LIST}, {"i915_gem_inactive", i915_gem_object_list_info, 0, (void *) INACTIVE_LIST}, + {"i915_gem_pinned", i915_gem_object_list_info, 0, (void *) PINNED_LIST}, {"i915_gem_pageflip", i915_gem_pageflip_info, 0}, {"i915_gem_request", i915_gem_request_info, 0}, {"i915_gem_seqno", i915_gem_seqno_info, 0}, diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index ce8ff8f..12e9f85 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -569,6 +569,12 @@ typedef struct drm_i915_private { */ struct list_head inactive_list; + /** + * LRU list of objects which are not in the ringbuffer but + * are still pinned in the GTT. + */ + struct list_head pinned_list; + /** LRU list of objects with fence regs on them. */ struct list_head fence_list; diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index a8ddcd4..151fa43 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -1051,7 +1051,6 @@ i915_gem_set_domain_ioctl(struct drm_device *dev, void *data, ret = i915_gem_object_set_to_cpu_domain(obj, write_domain != 0); } - /* Maintain LRU order of "inactive" objects */ if (ret == 0 && i915_gem_object_is_inactive(obj_priv)) list_move_tail(&obj_priv->list, &dev_priv->mm.inactive_list); @@ -1552,7 +1551,7 @@ i915_gem_object_move_to_inactive(struct drm_gem_object *obj) i915_verify_inactive(dev, __FILE__, __LINE__); if (obj_priv->pin_count != 0) - list_del_init(&obj_priv->list); + list_move_tail(&obj_priv->list, &dev_priv->mm.pinned_list); else list_move_tail(&obj_priv->list, &dev_priv->mm.inactive_list); @@ -2044,9 +2043,7 @@ i915_gem_object_unbind(struct drm_gem_object *obj) obj_priv->gtt_space = NULL; } - /* Remove ourselves from the LRU list if present. */ - if (!list_empty(&obj_priv->list)) - list_del_init(&obj_priv->list); + list_del_init(&obj_priv->list); if (i915_gem_object_is_purgeable(obj_priv)) i915_gem_object_truncate(obj); @@ -4030,6 +4027,7 @@ int i915_gem_object_pin(struct drm_gem_object *obj, uint32_t alignment) { struct drm_device *dev = obj->dev; + struct drm_i915_private *dev_priv = dev->dev_private; struct drm_i915_gem_object *obj_priv = to_intel_bo(obj); int ret; @@ -4065,9 +4063,9 @@ i915_gem_object_pin(struct drm_gem_object *obj, uint32_t alignment) if (obj_priv->pin_count == 1) { atomic_inc(&dev->pin_count); atomic_add(obj->size, &dev->pin_memory); - if (!obj_priv->active && - (obj->write_domain & I915_GEM_GPU_DOMAINS) == 0) - list_del_init(&obj_priv->list); + if (!obj_priv->active) + list_move_tail(&obj_priv->list, + &dev_priv->mm.pinned_list); } i915_verify_inactive(dev, __FILE__, __LINE__); @@ -4091,8 +4089,7 @@ i915_gem_object_unpin(struct drm_gem_object *obj) * the inactive list */ if (obj_priv->pin_count == 0) { - if (!obj_priv->active && - (obj->write_domain & I915_GEM_GPU_DOMAINS) == 0) + if (!obj_priv->active) list_move_tail(&obj_priv->list, &dev_priv->mm.inactive_list); atomic_dec(&dev->pin_count); @@ -4614,6 +4611,7 @@ i915_gem_load(struct drm_device *dev) INIT_LIST_HEAD(&dev_priv->mm.flushing_list); INIT_LIST_HEAD(&dev_priv->mm.gpu_write_list); INIT_LIST_HEAD(&dev_priv->mm.inactive_list); + INIT_LIST_HEAD(&dev_priv->mm.pinned_list); INIT_LIST_HEAD(&dev_priv->mm.fence_list); INIT_LIST_HEAD(&dev_priv->mm.deferred_free_list); INIT_LIST_HEAD(&dev_priv->render_ring.active_list); -- cgit v1.1 From 0e87d2b06cb4651c874d0b208d31c73addbd638b Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Tue, 7 Sep 2010 22:11:15 +0200 Subject: intel-gtt: initialize our own scratch page The intel gtt fake agp driver is the only agp driver to use dma address remapping. So it makes sense to fold this code back into the only user (and thus reduce the reliance on the agp code). This patch does the first step by initializing (and remapping) the scratch page in a new function intel_gtt_setup_scratch_page. Unfortunately intel_gtt_cleanup had to move to avoid a forward declaration. The new scratch page is not yet used, though. v2: Refactor out scratch page teardown. Suggested by Chris Wilson on irc. This makes it clear what's going on and results in a nice symmetry between setup and teardown. Signed-off-by: Daniel Vetter Signed-off-by: Chris Wilson --- drivers/char/agp/intel-gtt.c | 81 ++++++++++++++++++++++++++++++++++---------- 1 file changed, 64 insertions(+), 17 deletions(-) diff --git a/drivers/char/agp/intel-gtt.c b/drivers/char/agp/intel-gtt.c index 248ac5f..e386a44 100644 --- a/drivers/char/agp/intel-gtt.c +++ b/drivers/char/agp/intel-gtt.c @@ -35,6 +35,8 @@ */ #ifdef CONFIG_DMAR #define USE_PCI_DMA_API 1 +#else +#define USE_PCI_DMA_API 0 #endif /* Max amount of stolen space, anything above will be returned to Linux */ @@ -108,6 +110,8 @@ static struct _intel_private { struct page *i8xx_page; struct resource ifp_resource; int resource_valid; + struct page *scratch_page; + dma_addr_t scratch_page_dma; } intel_private; #define INTEL_GTT_GEN intel_private.driver->gen @@ -115,7 +119,7 @@ static struct _intel_private { #define IS_PINEVIEW intel_private.driver->is_pineview #define IS_IRONLAKE intel_private.driver->is_ironlake -#ifdef USE_PCI_DMA_API +#if USE_PCI_DMA_API static int intel_agp_map_page(struct page *page, dma_addr_t *ret) { *ret = pci_map_page(intel_private.pcidev, page, 0, @@ -540,6 +544,32 @@ static unsigned long intel_i810_mask_memory(struct agp_bridge_data *bridge, return addr | bridge->driver->masks[type].mask; } +static int intel_gtt_setup_scratch_page(void) +{ + struct page *page; + dma_addr_t dma_addr; + + page = alloc_page(GFP_KERNEL | GFP_DMA32 | __GFP_ZERO); + if (page == NULL) + return -ENOMEM; + get_page(page); + set_pages_uc(page, 1); + + if (USE_PCI_DMA_API && INTEL_GTT_GEN > 2) { + dma_addr = pci_map_page(intel_private.pcidev, page, 0, + PAGE_SIZE, PCI_DMA_BIDIRECTIONAL); + if (pci_dma_mapping_error(intel_private.pcidev, dma_addr)) + return -EINVAL; + + intel_private.scratch_page_dma = dma_addr; + } else + intel_private.scratch_page_dma = page_to_phys(page); + + intel_private.scratch_page = page; + + return 0; +} + static const struct aper_size_info_fixed const intel_fake_agp_sizes[] = { {128, 32768, 5}, /* The 64M mode still requires a 128k gatt */ @@ -794,6 +824,29 @@ static unsigned int intel_gtt_mappable_entries(void) return aperture_size >> PAGE_SHIFT; } +static void intel_gtt_teardown_scratch_page(void) +{ + set_pages_wb(intel_private.scratch_page, 1); + pci_unmap_page(intel_private.pcidev, intel_private.scratch_page_dma, + PAGE_SIZE, PCI_DMA_BIDIRECTIONAL); + put_page(intel_private.scratch_page); + __free_page(intel_private.scratch_page); +} + +static void intel_gtt_cleanup(void) +{ + if (intel_private.i9xx_flush_page) + iounmap(intel_private.i9xx_flush_page); + if (intel_private.resource_valid) + release_resource(&intel_private.ifp_resource); + intel_private.ifp_resource.start = 0; + intel_private.resource_valid = 0; + iounmap(intel_private.gtt); + iounmap(intel_private.registers); + + intel_gtt_teardown_scratch_page(); +} + static int intel_gtt_init(void) { u32 gtt_map_size; @@ -825,6 +878,12 @@ static int intel_gtt_init(void) return -ENOMEM; } + ret = intel_gtt_setup_scratch_page(); + if (ret != 0) { + intel_gtt_cleanup(); + return ret; + } + return 0; } @@ -1174,18 +1233,6 @@ static int intel_i9xx_configure(void) return 0; } -static void intel_gtt_cleanup(void) -{ - if (intel_private.i9xx_flush_page) - iounmap(intel_private.i9xx_flush_page); - if (intel_private.resource_valid) - release_resource(&intel_private.ifp_resource); - intel_private.ifp_resource.start = 0; - intel_private.resource_valid = 0; - iounmap(intel_private.gtt); - iounmap(intel_private.registers); -} - static void intel_i915_chipset_flush(struct agp_bridge_data *bridge) { if (intel_private.i9xx_flush_page) @@ -1416,7 +1463,7 @@ static const struct agp_bridge_driver intel_915_driver = { .agp_destroy_pages = agp_generic_destroy_pages, .agp_type_to_mask_type = intel_i830_type_to_mask_type, .chipset_flush = intel_i915_chipset_flush, -#ifdef USE_PCI_DMA_API +#if USE_PCI_DMA_API .agp_map_page = intel_agp_map_page, .agp_unmap_page = intel_agp_unmap_page, .agp_map_memory = intel_agp_map_memory, @@ -1449,7 +1496,7 @@ static const struct agp_bridge_driver intel_i965_driver = { .agp_destroy_pages = agp_generic_destroy_pages, .agp_type_to_mask_type = intel_i830_type_to_mask_type, .chipset_flush = intel_i915_chipset_flush, -#ifdef USE_PCI_DMA_API +#if USE_PCI_DMA_API .agp_map_page = intel_agp_map_page, .agp_unmap_page = intel_agp_unmap_page, .agp_map_memory = intel_agp_map_memory, @@ -1482,7 +1529,7 @@ static const struct agp_bridge_driver intel_gen6_driver = { .agp_destroy_pages = agp_generic_destroy_pages, .agp_type_to_mask_type = intel_gen6_type_to_mask_type, .chipset_flush = intel_i915_chipset_flush, -#ifdef USE_PCI_DMA_API +#if USE_PCI_DMA_API .agp_map_page = intel_agp_map_page, .agp_unmap_page = intel_agp_unmap_page, .agp_map_memory = intel_agp_map_memory, @@ -1515,7 +1562,7 @@ static const struct agp_bridge_driver intel_g33_driver = { .agp_destroy_pages = agp_generic_destroy_pages, .agp_type_to_mask_type = intel_i830_type_to_mask_type, .chipset_flush = intel_i915_chipset_flush, -#ifdef USE_PCI_DMA_API +#if USE_PCI_DMA_API .agp_map_page = intel_agp_map_page, .agp_unmap_page = intel_agp_unmap_page, .agp_map_memory = intel_agp_map_memory, -- cgit v1.1 From 351bb278d2fd2df93526c15f37500070347328b4 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Tue, 7 Sep 2010 22:41:04 +0200 Subject: intel-gtt: introduce pte write function for i8xx/i915/i945 And put it to use in the gtt configuration code that writes the scratch page addr in all gtt ptes. This makes intel_i830_configure generic, hence rename it to intel_fake_agp_configure. Signed-off-by: Daniel Vetter Signed-off-by: Chris Wilson --- drivers/char/agp/intel-gtt.c | 41 ++++++++++++++++++++++++++++++++--------- 1 file changed, 32 insertions(+), 9 deletions(-) diff --git a/drivers/char/agp/intel-gtt.c b/drivers/char/agp/intel-gtt.c index e386a44..4d768e0 100644 --- a/drivers/char/agp/intel-gtt.c +++ b/drivers/char/agp/intel-gtt.c @@ -90,6 +90,10 @@ struct intel_gtt_driver { unsigned int is_ironlake : 1; /* Chipset specific GTT setup */ int (*setup)(void); + void (*write_entry)(dma_addr_t addr, unsigned int entry, unsigned int flags); + /* Flags is a more or less chipset specific opaque value. + * For chipsets that need to support old ums (non-gem) code, this + * needs to be identical to the various supported agp memory types! */ }; static struct _intel_private { @@ -954,6 +958,23 @@ static void intel_i830_chipset_flush(struct agp_bridge_data *bridge) printk(KERN_ERR "Timed out waiting for cache flush.\n"); } +static void i830_write_entry(dma_addr_t addr, unsigned int entry, + unsigned int flags) +{ + u32 pte_flags = I810_PTE_VALID; + + switch (flags) { + case AGP_DCACHE_MEMORY: + pte_flags |= I810_PTE_LOCAL; + break; + case AGP_USER_CACHED_MEMORY: + pte_flags |= I830_PTE_SYSTEM_CACHED; + break; + } + + writel(addr | pte_flags, intel_private.gtt + entry); +} + static void intel_enable_gtt(void) { u32 gma_addr; @@ -1011,7 +1032,7 @@ static int intel_fake_agp_free_gatt_table(struct agp_bridge_data *bridge) return 0; } -static int intel_i830_configure(void) +static int intel_fake_agp_configure(void) { int i; @@ -1019,13 +1040,12 @@ static int intel_i830_configure(void) agp_bridge->gart_bus_addr = intel_private.gma_bus_addr; - if (agp_bridge->driver->needs_scratch_page) { - for (i = intel_private.base.gtt_stolen_entries; - i < intel_private.base.gtt_total_entries; i++) { - writel(agp_bridge->scratch_page, intel_private.gtt+i); - } - readl(intel_private.gtt+i-1); /* PCI Posting. */ + for (i = intel_private.base.gtt_stolen_entries; + i < intel_private.base.gtt_total_entries; i++) { + intel_private.driver->write_entry(intel_private.scratch_page_dma, + i, 0); } + readl(intel_private.gtt+i-1); /* PCI Posting. */ global_cache_flush(); @@ -1417,7 +1437,7 @@ static const struct agp_bridge_driver intel_830_driver = { .aperture_sizes = intel_fake_agp_sizes, .num_aperture_sizes = ARRAY_SIZE(intel_fake_agp_sizes), .needs_scratch_page = true, - .configure = intel_i830_configure, + .configure = intel_fake_agp_configure, .fetch_size = intel_fake_agp_fetch_size, .cleanup = intel_gtt_cleanup, .mask_memory = intel_i810_mask_memory, @@ -1444,7 +1464,7 @@ static const struct agp_bridge_driver intel_915_driver = { .aperture_sizes = intel_fake_agp_sizes, .num_aperture_sizes = ARRAY_SIZE(intel_fake_agp_sizes), .needs_scratch_page = true, - .configure = intel_i9xx_configure, + .configure = intel_fake_agp_configure, .fetch_size = intel_fake_agp_fetch_size, .cleanup = intel_gtt_cleanup, .mask_memory = intel_i810_mask_memory, @@ -1573,10 +1593,13 @@ static const struct agp_bridge_driver intel_g33_driver = { static const struct intel_gtt_driver i8xx_gtt_driver = { .gen = 2, .setup = i830_setup, + .write_entry = i830_write_entry, }; static const struct intel_gtt_driver i915_gtt_driver = { .gen = 3, .setup = i9xx_setup, + /* i945 is the last gpu to need phys mem (for overlay and cursors). */ + .write_entry = i830_write_entry, }; static const struct intel_gtt_driver g33_gtt_driver = { .gen = 3, -- cgit v1.1 From a6963596a13e62f8e65b1cf3403a330ff2db407c Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Sat, 11 Sep 2010 14:01:43 +0200 Subject: intel-gtt: introduce pte write function for g33/i965/gm45 Like for the i830. Signed-off-by: Daniel Vetter Signed-off-by: Chris Wilson --- drivers/char/agp/intel-gtt.c | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/drivers/char/agp/intel-gtt.c b/drivers/char/agp/intel-gtt.c index 4d768e0..9d25ebd 100644 --- a/drivers/char/agp/intel-gtt.c +++ b/drivers/char/agp/intel-gtt.c @@ -1334,6 +1334,14 @@ static int intel_i915_remove_entries(struct agp_memory *mem, off_t pg_start, return 0; } +static void i965_write_entry(dma_addr_t addr, unsigned int entry, + unsigned int flags) +{ + /* Shift high bits down */ + addr |= (addr >> 28) & 0xf0; + writel(addr | I810_PTE_VALID, intel_private.gtt + entry); +} + static int i9xx_setup(void) { u32 reg_addr; @@ -1497,7 +1505,7 @@ static const struct agp_bridge_driver intel_i965_driver = { .aperture_sizes = intel_fake_agp_sizes, .num_aperture_sizes = ARRAY_SIZE(intel_fake_agp_sizes), .needs_scratch_page = true, - .configure = intel_i9xx_configure, + .configure = intel_fake_agp_configure, .fetch_size = intel_fake_agp_fetch_size, .cleanup = intel_gtt_cleanup, .mask_memory = intel_i965_mask_memory, @@ -1563,7 +1571,7 @@ static const struct agp_bridge_driver intel_g33_driver = { .aperture_sizes = intel_fake_agp_sizes, .num_aperture_sizes = ARRAY_SIZE(intel_fake_agp_sizes), .needs_scratch_page = true, - .configure = intel_i9xx_configure, + .configure = intel_fake_agp_configure, .fetch_size = intel_fake_agp_fetch_size, .cleanup = intel_gtt_cleanup, .mask_memory = intel_i965_mask_memory, @@ -1605,24 +1613,29 @@ static const struct intel_gtt_driver g33_gtt_driver = { .gen = 3, .is_g33 = 1, .setup = i9xx_setup, + .write_entry = i965_write_entry, }; static const struct intel_gtt_driver pineview_gtt_driver = { .gen = 3, .is_pineview = 1, .is_g33 = 1, .setup = i9xx_setup, + .write_entry = i965_write_entry, }; static const struct intel_gtt_driver i965_gtt_driver = { .gen = 4, .setup = i9xx_setup, + .write_entry = i965_write_entry, }; static const struct intel_gtt_driver g4x_gtt_driver = { .gen = 5, .setup = i9xx_setup, + .write_entry = i965_write_entry, }; static const struct intel_gtt_driver ironlake_gtt_driver = { .gen = 5, .is_ironlake = 1, .setup = i9xx_setup, + .write_entry = i965_write_entry, }; static const struct intel_gtt_driver sandybridge_gtt_driver = { .gen = 6, -- cgit v1.1 From 97ef1bdd0bc75bce7b2058e9c432b6c277dcf4d3 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Thu, 9 Sep 2010 17:52:20 +0200 Subject: intel-gtt: introduce pte write function for gen6 Like for i830. intel_i9xx_configure is now unused, so kill it. Signed-off-by: Daniel Vetter Signed-off-by: Chris Wilson --- drivers/char/agp/intel-gtt.c | 48 ++++++++++++++++++++++++-------------------- 1 file changed, 26 insertions(+), 22 deletions(-) diff --git a/drivers/char/agp/intel-gtt.c b/drivers/char/agp/intel-gtt.c index 9d25ebd..1de45f9 100644 --- a/drivers/char/agp/intel-gtt.c +++ b/drivers/char/agp/intel-gtt.c @@ -1232,27 +1232,6 @@ static void intel_i9xx_setup_flush(void) "can't ioremap flush page - no chipset flushing\n"); } -static int intel_i9xx_configure(void) -{ - int i; - - intel_enable_gtt(); - - agp_bridge->gart_bus_addr = intel_private.gma_bus_addr; - - if (agp_bridge->driver->needs_scratch_page) { - for (i = intel_private.base.gtt_stolen_entries; i < - intel_private.base.gtt_total_entries; i++) { - writel(agp_bridge->scratch_page, intel_private.gtt+i); - } - readl(intel_private.gtt+i-1); /* PCI Posting. */ - } - - global_cache_flush(); - - return 0; -} - static void intel_i915_chipset_flush(struct agp_bridge_data *bridge) { if (intel_private.i9xx_flush_page) @@ -1342,6 +1321,30 @@ static void i965_write_entry(dma_addr_t addr, unsigned int entry, writel(addr | I810_PTE_VALID, intel_private.gtt + entry); } +static void gen6_write_entry(dma_addr_t addr, unsigned int entry, + unsigned int flags) +{ + unsigned int type_mask = flags & ~AGP_USER_CACHED_MEMORY_GFDT; + unsigned int gfdt = flags & AGP_USER_CACHED_MEMORY_GFDT; + u32 pte_flags; + + if (type_mask == AGP_USER_UNCACHED_MEMORY) + pte_flags = GEN6_PTE_UNCACHED; + else if (type_mask == AGP_USER_CACHED_MEMORY_LLC_MLC) { + pte_flags = GEN6_PTE_LLC; + if (gfdt) + pte_flags |= GEN6_PTE_GFDT; + } else { /* set 'normal'/'cached' to LLC by default */ + pte_flags = GEN6_PTE_LLC_MLC; + if (gfdt) + pte_flags |= GEN6_PTE_GFDT; + } + + /* gen6 has bit11-4 for physical addr bit39-32 */ + addr |= (addr >> 28) & 0xff0; + writel(addr | pte_flags, intel_private.gtt + entry); +} + static int i9xx_setup(void) { u32 reg_addr; @@ -1538,7 +1541,7 @@ static const struct agp_bridge_driver intel_gen6_driver = { .aperture_sizes = intel_fake_agp_sizes, .num_aperture_sizes = ARRAY_SIZE(intel_fake_agp_sizes), .needs_scratch_page = true, - .configure = intel_i9xx_configure, + .configure = intel_fake_agp_configure, .fetch_size = intel_fake_agp_fetch_size, .cleanup = intel_gtt_cleanup, .mask_memory = intel_gen6_mask_memory, @@ -1640,6 +1643,7 @@ static const struct intel_gtt_driver ironlake_gtt_driver = { static const struct intel_gtt_driver sandybridge_gtt_driver = { .gen = 6, .setup = i9xx_setup, + .write_entry = gen6_write_entry, }; /* Table to describe Intel GMCH and AGP/PCIE GART drivers. At least one of -- cgit v1.1 From d0b6dc4b930e3be9c02cc9638f02e14d271d5f0d Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Thu, 9 Sep 2010 18:11:41 +0200 Subject: intel-gtt: drop agp scratch page support stuff intel-gtt.c now handles the scratch page itself, so drop all that was just there to support it. Signed-off-by: Daniel Vetter Signed-off-by: Chris Wilson --- drivers/char/agp/intel-gtt.c | 28 ---------------------------- 1 file changed, 28 deletions(-) diff --git a/drivers/char/agp/intel-gtt.c b/drivers/char/agp/intel-gtt.c index 1de45f9..64a62d9 100644 --- a/drivers/char/agp/intel-gtt.c +++ b/drivers/char/agp/intel-gtt.c @@ -124,21 +124,6 @@ static struct _intel_private { #define IS_IRONLAKE intel_private.driver->is_ironlake #if USE_PCI_DMA_API -static int intel_agp_map_page(struct page *page, dma_addr_t *ret) -{ - *ret = pci_map_page(intel_private.pcidev, page, 0, - PAGE_SIZE, PCI_DMA_BIDIRECTIONAL); - if (pci_dma_mapping_error(intel_private.pcidev, *ret)) - return -EINVAL; - return 0; -} - -static void intel_agp_unmap_page(struct page *page, dma_addr_t dma) -{ - pci_unmap_page(intel_private.pcidev, dma, - PAGE_SIZE, PCI_DMA_BIDIRECTIONAL); -} - static void intel_agp_free_sglist(struct agp_memory *mem) { struct sg_table st; @@ -1447,7 +1432,6 @@ static const struct agp_bridge_driver intel_830_driver = { .size_type = FIXED_APER_SIZE, .aperture_sizes = intel_fake_agp_sizes, .num_aperture_sizes = ARRAY_SIZE(intel_fake_agp_sizes), - .needs_scratch_page = true, .configure = intel_fake_agp_configure, .fetch_size = intel_fake_agp_fetch_size, .cleanup = intel_gtt_cleanup, @@ -1474,7 +1458,6 @@ static const struct agp_bridge_driver intel_915_driver = { .size_type = FIXED_APER_SIZE, .aperture_sizes = intel_fake_agp_sizes, .num_aperture_sizes = ARRAY_SIZE(intel_fake_agp_sizes), - .needs_scratch_page = true, .configure = intel_fake_agp_configure, .fetch_size = intel_fake_agp_fetch_size, .cleanup = intel_gtt_cleanup, @@ -1495,8 +1478,6 @@ static const struct agp_bridge_driver intel_915_driver = { .agp_type_to_mask_type = intel_i830_type_to_mask_type, .chipset_flush = intel_i915_chipset_flush, #if USE_PCI_DMA_API - .agp_map_page = intel_agp_map_page, - .agp_unmap_page = intel_agp_unmap_page, .agp_map_memory = intel_agp_map_memory, .agp_unmap_memory = intel_agp_unmap_memory, #endif @@ -1507,7 +1488,6 @@ static const struct agp_bridge_driver intel_i965_driver = { .size_type = FIXED_APER_SIZE, .aperture_sizes = intel_fake_agp_sizes, .num_aperture_sizes = ARRAY_SIZE(intel_fake_agp_sizes), - .needs_scratch_page = true, .configure = intel_fake_agp_configure, .fetch_size = intel_fake_agp_fetch_size, .cleanup = intel_gtt_cleanup, @@ -1528,8 +1508,6 @@ static const struct agp_bridge_driver intel_i965_driver = { .agp_type_to_mask_type = intel_i830_type_to_mask_type, .chipset_flush = intel_i915_chipset_flush, #if USE_PCI_DMA_API - .agp_map_page = intel_agp_map_page, - .agp_unmap_page = intel_agp_unmap_page, .agp_map_memory = intel_agp_map_memory, .agp_unmap_memory = intel_agp_unmap_memory, #endif @@ -1540,7 +1518,6 @@ static const struct agp_bridge_driver intel_gen6_driver = { .size_type = FIXED_APER_SIZE, .aperture_sizes = intel_fake_agp_sizes, .num_aperture_sizes = ARRAY_SIZE(intel_fake_agp_sizes), - .needs_scratch_page = true, .configure = intel_fake_agp_configure, .fetch_size = intel_fake_agp_fetch_size, .cleanup = intel_gtt_cleanup, @@ -1561,8 +1538,6 @@ static const struct agp_bridge_driver intel_gen6_driver = { .agp_type_to_mask_type = intel_gen6_type_to_mask_type, .chipset_flush = intel_i915_chipset_flush, #if USE_PCI_DMA_API - .agp_map_page = intel_agp_map_page, - .agp_unmap_page = intel_agp_unmap_page, .agp_map_memory = intel_agp_map_memory, .agp_unmap_memory = intel_agp_unmap_memory, #endif @@ -1573,7 +1548,6 @@ static const struct agp_bridge_driver intel_g33_driver = { .size_type = FIXED_APER_SIZE, .aperture_sizes = intel_fake_agp_sizes, .num_aperture_sizes = ARRAY_SIZE(intel_fake_agp_sizes), - .needs_scratch_page = true, .configure = intel_fake_agp_configure, .fetch_size = intel_fake_agp_fetch_size, .cleanup = intel_gtt_cleanup, @@ -1594,8 +1568,6 @@ static const struct agp_bridge_driver intel_g33_driver = { .agp_type_to_mask_type = intel_i830_type_to_mask_type, .chipset_flush = intel_i915_chipset_flush, #if USE_PCI_DMA_API - .agp_map_page = intel_agp_map_page, - .agp_unmap_page = intel_agp_unmap_page, .agp_map_memory = intel_agp_map_memory, .agp_unmap_memory = intel_agp_unmap_memory, #endif -- cgit v1.1 From a87aa5cc0074fea871c8c6d2660d9b6cd7699d3d Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Thu, 9 Sep 2010 18:17:34 +0200 Subject: agp: kill agp_(map|unmap)_page Only used to remap the scratch page. Now that intel-gtt does this itself, kill the support code. Cc: Dave Airlie Signed-off-by: Daniel Vetter Signed-off-by: Chris Wilson --- drivers/char/agp/agp.h | 2 -- drivers/char/agp/backend.c | 22 +--------------------- 2 files changed, 1 insertion(+), 23 deletions(-) diff --git a/drivers/char/agp/agp.h b/drivers/char/agp/agp.h index 1204909..04ad0bb 100644 --- a/drivers/char/agp/agp.h +++ b/drivers/char/agp/agp.h @@ -122,8 +122,6 @@ struct agp_bridge_driver { int (*agp_type_to_mask_type) (struct agp_bridge_data *, int); void (*chipset_flush)(struct agp_bridge_data *); - int (*agp_map_page)(struct page *page, dma_addr_t *ret); - void (*agp_unmap_page)(struct page *page, dma_addr_t dma); int (*agp_map_memory)(struct agp_memory *mem); void (*agp_unmap_memory)(struct agp_memory *mem); }; diff --git a/drivers/char/agp/backend.c b/drivers/char/agp/backend.c index ee4f855..f27d0d0 100644 --- a/drivers/char/agp/backend.c +++ b/drivers/char/agp/backend.c @@ -151,17 +151,7 @@ static int agp_backend_initialize(struct agp_bridge_data *bridge) } bridge->scratch_page_page = page; - if (bridge->driver->agp_map_page) { - if (bridge->driver->agp_map_page(page, - &bridge->scratch_page_dma)) { - dev_err(&bridge->dev->dev, - "unable to dma-map scratch page\n"); - rc = -ENOMEM; - goto err_out_nounmap; - } - } else { - bridge->scratch_page_dma = page_to_phys(page); - } + bridge->scratch_page_dma = page_to_phys(page); bridge->scratch_page = bridge->driver->mask_memory(bridge, bridge->scratch_page_dma, 0); @@ -204,12 +194,6 @@ static int agp_backend_initialize(struct agp_bridge_data *bridge) return 0; err_out: - if (bridge->driver->needs_scratch_page && - bridge->driver->agp_unmap_page) { - bridge->driver->agp_unmap_page(bridge->scratch_page_page, - bridge->scratch_page_dma); - } -err_out_nounmap: if (bridge->driver->needs_scratch_page) { void *va = page_address(bridge->scratch_page_page); @@ -240,10 +224,6 @@ static void agp_backend_cleanup(struct agp_bridge_data *bridge) bridge->driver->needs_scratch_page) { void *va = page_address(bridge->scratch_page_page); - if (bridge->driver->agp_unmap_page) - bridge->driver->agp_unmap_page(bridge->scratch_page_page, - bridge->scratch_page_dma); - bridge->driver->agp_destroy_page(va, AGP_PAGE_DESTROY_UNMAP); bridge->driver->agp_destroy_page(va, AGP_PAGE_DESTROY_FREE); } -- cgit v1.1 From 5cbecafce4ee8ab73c194911e01a77a7a07f034e Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Sat, 11 Sep 2010 21:31:04 +0200 Subject: intel-gtt: generic (insert|remove)_entries for i830 Well, not all too generic because it does not yet support dmar. Add a new function check_flags to ensure that non-gem code does not try to screw us over. v2: Beautify i830_check_flags with an idea from Chris Wilson. Signed-off-by: Daniel Vetter Signed-off-by: Chris Wilson --- drivers/char/agp/intel-gtt.c | 53 +++++++++++++++++++++++--------------------- 1 file changed, 28 insertions(+), 25 deletions(-) diff --git a/drivers/char/agp/intel-gtt.c b/drivers/char/agp/intel-gtt.c index 64a62d9..c1b766d 100644 --- a/drivers/char/agp/intel-gtt.c +++ b/drivers/char/agp/intel-gtt.c @@ -94,6 +94,7 @@ struct intel_gtt_driver { /* Flags is a more or less chipset specific opaque value. * For chipsets that need to support old ums (non-gem) code, this * needs to be identical to the various supported agp memory types! */ + bool (*check_flags)(unsigned int flags); }; static struct _intel_private { @@ -1037,20 +1038,28 @@ static int intel_fake_agp_configure(void) return 0; } -static int intel_i830_insert_entries(struct agp_memory *mem, off_t pg_start, - int type) +static bool i830_check_flags(unsigned int flags) { - int i, j, num_entries; - void *temp; + switch (flags) { + case 0: + case AGP_PHYS_MEMORY: + case AGP_USER_CACHED_MEMORY: + case AGP_USER_MEMORY: + return true; + } + + return false; +} + +static int intel_fake_agp_insert_entries(struct agp_memory *mem, + off_t pg_start, int type) +{ + int i, j; int ret = -EINVAL; - int mask_type; if (mem->page_count == 0) goto out; - temp = agp_bridge->current_size; - num_entries = A_SIZE_FIX(temp)->num_entries; - if (pg_start < intel_private.base.gtt_stolen_entries) { dev_printk(KERN_DEBUG, &intel_private.pcidev->dev, "pg_start == 0x%.8lx, gtt_stolen_entries == 0x%.8x\n", @@ -1061,29 +1070,21 @@ static int intel_i830_insert_entries(struct agp_memory *mem, off_t pg_start, goto out_err; } - if ((pg_start + mem->page_count) > num_entries) + if ((pg_start + mem->page_count) > intel_private.base.gtt_total_entries) goto out_err; - /* The i830 can't check the GTT for entries since its read only, - * depend on the caller to make the correct offset decisions. - */ - if (type != mem->type) goto out_err; - mask_type = agp_bridge->driver->agp_type_to_mask_type(agp_bridge, type); - - if (mask_type != 0 && mask_type != AGP_PHYS_MEMORY && - mask_type != INTEL_AGP_CACHED_MEMORY) + if (!intel_private.driver->check_flags(type)) goto out_err; if (!mem->is_flushed) global_cache_flush(); for (i = 0, j = pg_start; i < mem->page_count; i++, j++) { - writel(agp_bridge->driver->mask_memory(agp_bridge, - page_to_phys(mem->pages[i]), mask_type), - intel_private.gtt+j); + intel_private.driver->write_entry(page_to_phys(mem->pages[i]), + j, type); } readl(intel_private.gtt+j-1); @@ -1094,8 +1095,8 @@ out_err: return ret; } -static int intel_i830_remove_entries(struct agp_memory *mem, off_t pg_start, - int type) +static int intel_fake_agp_remove_entries(struct agp_memory *mem, + off_t pg_start, int type) { int i; @@ -1109,7 +1110,8 @@ static int intel_i830_remove_entries(struct agp_memory *mem, off_t pg_start, } for (i = pg_start; i < (mem->page_count + pg_start); i++) { - writel(agp_bridge->scratch_page, intel_private.gtt+i); + intel_private.driver->write_entry(intel_private.scratch_page_dma, + i, 0); } readl(intel_private.gtt+i-1); @@ -1441,8 +1443,8 @@ static const struct agp_bridge_driver intel_830_driver = { .cache_flush = global_cache_flush, .create_gatt_table = intel_fake_agp_create_gatt_table, .free_gatt_table = intel_fake_agp_free_gatt_table, - .insert_memory = intel_i830_insert_entries, - .remove_memory = intel_i830_remove_entries, + .insert_memory = intel_fake_agp_insert_entries, + .remove_memory = intel_fake_agp_remove_entries, .alloc_by_type = intel_fake_agp_alloc_by_type, .free_by_type = intel_i810_free_by_type, .agp_alloc_page = agp_generic_alloc_page, @@ -1577,6 +1579,7 @@ static const struct intel_gtt_driver i8xx_gtt_driver = { .gen = 2, .setup = i830_setup, .write_entry = i830_write_entry, + .check_flags = i830_check_flags, }; static const struct intel_gtt_driver i915_gtt_driver = { .gen = 3, -- cgit v1.1 From fefaa70f0c7fa406492039e35b69b83fc13e163a Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Sat, 11 Sep 2010 22:12:11 +0200 Subject: intel-gtt: generic (insert|remove)_entries for i915 Beef up the generic version to support dmar. Otherwise like for the i830. v2: Don't try to DMA remap on resume for already remapped pages. Signed-off-by: Daniel Vetter Signed-off-by: Chris Wilson --- drivers/char/agp/intel-gtt.c | 60 ++++++++++++++++++++++++++++++++++++-------- 1 file changed, 49 insertions(+), 11 deletions(-) diff --git a/drivers/char/agp/intel-gtt.c b/drivers/char/agp/intel-gtt.c index c1b766d..f05c364 100644 --- a/drivers/char/agp/intel-gtt.c +++ b/drivers/char/agp/intel-gtt.c @@ -124,7 +124,6 @@ static struct _intel_private { #define IS_PINEVIEW intel_private.driver->is_pineview #define IS_IRONLAKE intel_private.driver->is_ironlake -#if USE_PCI_DMA_API static void intel_agp_free_sglist(struct agp_memory *mem) { struct sg_table st; @@ -144,6 +143,9 @@ static int intel_agp_map_memory(struct agp_memory *mem) struct scatterlist *sg; int i; + if (mem->sg_list) + return 0; /* already mapped (for e.g. resume */ + DBG("try mapping %lu pages\n", (unsigned long)mem->page_count); if (sg_alloc_table(&st, mem->page_count, GFP_KERNEL)) @@ -175,6 +177,7 @@ static void intel_agp_unmap_memory(struct agp_memory *mem) intel_agp_free_sglist(mem); } +#if USE_PCI_DMA_API static void intel_agp_insert_sg_entries(struct agp_memory *mem, off_t pg_start, int mask_type) { @@ -1051,6 +1054,31 @@ static bool i830_check_flags(unsigned int flags) return false; } +static void intel_gtt_insert_sg_entries(struct scatterlist *sg_list, + unsigned int sg_len, + unsigned int pg_start, + unsigned int flags) +{ + struct scatterlist *sg; + unsigned int len, m; + int i, j; + + j = pg_start; + + /* sg may merge pages, but we have to separate + * per-page addr for GTT */ + for_each_sg(sg_list, sg, sg_len, i) { + len = sg_dma_len(sg) >> PAGE_SHIFT; + for (m = 0; m < len; m++) { + dma_addr_t addr = sg_dma_address(sg) + (m << PAGE_SHIFT); + intel_private.driver->write_entry(addr, + j, flags); + j++; + } + } + readl(intel_private.gtt+j-1); +} + static int intel_fake_agp_insert_entries(struct agp_memory *mem, off_t pg_start, int type) { @@ -1082,11 +1110,21 @@ static int intel_fake_agp_insert_entries(struct agp_memory *mem, if (!mem->is_flushed) global_cache_flush(); - for (i = 0, j = pg_start; i < mem->page_count; i++, j++) { - intel_private.driver->write_entry(page_to_phys(mem->pages[i]), - j, type); + if (USE_PCI_DMA_API && INTEL_GTT_GEN > 2) { + ret = intel_agp_map_memory(mem); + if (ret != 0) + return ret; + + intel_gtt_insert_sg_entries(mem->sg_list, mem->num_sg, + pg_start, type); + } else { + for (i = 0, j = pg_start; i < mem->page_count; i++, j++) { + dma_addr_t addr = page_to_phys(mem->pages[i]); + intel_private.driver->write_entry(addr, + j, type); + } + readl(intel_private.gtt+j-1); } - readl(intel_private.gtt+j-1); out: ret = 0; @@ -1109,6 +1147,9 @@ static int intel_fake_agp_remove_entries(struct agp_memory *mem, return -EINVAL; } + if (USE_PCI_DMA_API && INTEL_GTT_GEN > 2) + intel_agp_unmap_memory(mem); + for (i = pg_start; i < (mem->page_count + pg_start); i++) { intel_private.driver->write_entry(intel_private.scratch_page_dma, i, 0); @@ -1469,8 +1510,8 @@ static const struct agp_bridge_driver intel_915_driver = { .cache_flush = global_cache_flush, .create_gatt_table = intel_fake_agp_create_gatt_table, .free_gatt_table = intel_fake_agp_free_gatt_table, - .insert_memory = intel_i915_insert_entries, - .remove_memory = intel_i915_remove_entries, + .insert_memory = intel_fake_agp_insert_entries, + .remove_memory = intel_fake_agp_remove_entries, .alloc_by_type = intel_fake_agp_alloc_by_type, .free_by_type = intel_i810_free_by_type, .agp_alloc_page = agp_generic_alloc_page, @@ -1479,10 +1520,6 @@ static const struct agp_bridge_driver intel_915_driver = { .agp_destroy_pages = agp_generic_destroy_pages, .agp_type_to_mask_type = intel_i830_type_to_mask_type, .chipset_flush = intel_i915_chipset_flush, -#if USE_PCI_DMA_API - .agp_map_memory = intel_agp_map_memory, - .agp_unmap_memory = intel_agp_unmap_memory, -#endif }; static const struct agp_bridge_driver intel_i965_driver = { @@ -1586,6 +1623,7 @@ static const struct intel_gtt_driver i915_gtt_driver = { .setup = i9xx_setup, /* i945 is the last gpu to need phys mem (for overlay and cursors). */ .write_entry = i830_write_entry, + .check_flags = i830_check_flags, }; static const struct intel_gtt_driver g33_gtt_driver = { .gen = 3, -- cgit v1.1 From 450f2b3d51025a1749b694ee13f0e4e23ed58750 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Sat, 11 Sep 2010 23:48:25 +0200 Subject: intel-gtt: generic (insert|remove)_entries for g33/i965 Like for the i915. Signed-off-by: Daniel Vetter Signed-off-by: Chris Wilson --- drivers/char/agp/intel-gtt.c | 21 +++++++++------------ 1 file changed, 9 insertions(+), 12 deletions(-) diff --git a/drivers/char/agp/intel-gtt.c b/drivers/char/agp/intel-gtt.c index f05c364..dc06b23c 100644 --- a/drivers/char/agp/intel-gtt.c +++ b/drivers/char/agp/intel-gtt.c @@ -1536,8 +1536,8 @@ static const struct agp_bridge_driver intel_i965_driver = { .cache_flush = global_cache_flush, .create_gatt_table = intel_fake_agp_create_gatt_table, .free_gatt_table = intel_fake_agp_free_gatt_table, - .insert_memory = intel_i915_insert_entries, - .remove_memory = intel_i915_remove_entries, + .insert_memory = intel_fake_agp_insert_entries, + .remove_memory = intel_fake_agp_remove_entries, .alloc_by_type = intel_fake_agp_alloc_by_type, .free_by_type = intel_i810_free_by_type, .agp_alloc_page = agp_generic_alloc_page, @@ -1546,10 +1546,6 @@ static const struct agp_bridge_driver intel_i965_driver = { .agp_destroy_pages = agp_generic_destroy_pages, .agp_type_to_mask_type = intel_i830_type_to_mask_type, .chipset_flush = intel_i915_chipset_flush, -#if USE_PCI_DMA_API - .agp_map_memory = intel_agp_map_memory, - .agp_unmap_memory = intel_agp_unmap_memory, -#endif }; static const struct agp_bridge_driver intel_gen6_driver = { @@ -1596,8 +1592,8 @@ static const struct agp_bridge_driver intel_g33_driver = { .cache_flush = global_cache_flush, .create_gatt_table = intel_fake_agp_create_gatt_table, .free_gatt_table = intel_fake_agp_free_gatt_table, - .insert_memory = intel_i915_insert_entries, - .remove_memory = intel_i915_remove_entries, + .insert_memory = intel_fake_agp_insert_entries, + .remove_memory = intel_fake_agp_remove_entries, .alloc_by_type = intel_fake_agp_alloc_by_type, .free_by_type = intel_i810_free_by_type, .agp_alloc_page = agp_generic_alloc_page, @@ -1606,10 +1602,6 @@ static const struct agp_bridge_driver intel_g33_driver = { .agp_destroy_pages = agp_generic_destroy_pages, .agp_type_to_mask_type = intel_i830_type_to_mask_type, .chipset_flush = intel_i915_chipset_flush, -#if USE_PCI_DMA_API - .agp_map_memory = intel_agp_map_memory, - .agp_unmap_memory = intel_agp_unmap_memory, -#endif }; static const struct intel_gtt_driver i8xx_gtt_driver = { @@ -1630,28 +1622,33 @@ static const struct intel_gtt_driver g33_gtt_driver = { .is_g33 = 1, .setup = i9xx_setup, .write_entry = i965_write_entry, + .check_flags = i830_check_flags, }; static const struct intel_gtt_driver pineview_gtt_driver = { .gen = 3, .is_pineview = 1, .is_g33 = 1, .setup = i9xx_setup, .write_entry = i965_write_entry, + .check_flags = i830_check_flags, }; static const struct intel_gtt_driver i965_gtt_driver = { .gen = 4, .setup = i9xx_setup, .write_entry = i965_write_entry, + .check_flags = i830_check_flags, }; static const struct intel_gtt_driver g4x_gtt_driver = { .gen = 5, .setup = i9xx_setup, .write_entry = i965_write_entry, + .check_flags = i830_check_flags, }; static const struct intel_gtt_driver ironlake_gtt_driver = { .gen = 5, .is_ironlake = 1, .setup = i9xx_setup, .write_entry = i965_write_entry, + .check_flags = i830_check_flags, }; static const struct intel_gtt_driver sandybridge_gtt_driver = { .gen = 6, -- cgit v1.1 From 90cb149e1a85f8296daa1989c055db18fbf4ea88 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Sat, 11 Sep 2010 23:55:20 +0200 Subject: intel-gtt: generic (insert|remove)_entries for sandybridge Like before, but now with the added bonus of being able to kill quite a bit of no-longer userful code (the old dmar support stuff). Signed-off-by: Daniel Vetter Signed-off-by: Chris Wilson --- drivers/char/agp/intel-gtt.c | 144 +++---------------------------------------- 1 file changed, 8 insertions(+), 136 deletions(-) diff --git a/drivers/char/agp/intel-gtt.c b/drivers/char/agp/intel-gtt.c index dc06b23c..44722c6 100644 --- a/drivers/char/agp/intel-gtt.c +++ b/drivers/char/agp/intel-gtt.c @@ -177,61 +177,6 @@ static void intel_agp_unmap_memory(struct agp_memory *mem) intel_agp_free_sglist(mem); } -#if USE_PCI_DMA_API -static void intel_agp_insert_sg_entries(struct agp_memory *mem, - off_t pg_start, int mask_type) -{ - struct scatterlist *sg; - int i, j; - - j = pg_start; - - WARN_ON(!mem->num_sg); - - if (mem->num_sg == mem->page_count) { - for_each_sg(mem->sg_list, sg, mem->page_count, i) { - writel(agp_bridge->driver->mask_memory(agp_bridge, - sg_dma_address(sg), mask_type), - intel_private.gtt+j); - j++; - } - } else { - /* sg may merge pages, but we have to separate - * per-page addr for GTT */ - unsigned int len, m; - - for_each_sg(mem->sg_list, sg, mem->num_sg, i) { - len = sg_dma_len(sg) / PAGE_SIZE; - for (m = 0; m < len; m++) { - writel(agp_bridge->driver->mask_memory(agp_bridge, - sg_dma_address(sg) + m * PAGE_SIZE, - mask_type), - intel_private.gtt+j); - j++; - } - } - } - readl(intel_private.gtt+j-1); -} - -#else - -static void intel_agp_insert_sg_entries(struct agp_memory *mem, - off_t pg_start, int mask_type) -{ - int i, j; - - for (i = 0, j = pg_start; i < mem->page_count; i++, j++) { - writel(agp_bridge->driver->mask_memory(agp_bridge, - page_to_phys(mem->pages[i]), mask_type), - intel_private.gtt+j); - } - - readl(intel_private.gtt+j-1); -} - -#endif - static int intel_i810_fetch_size(void) { u32 smram_miscc; @@ -1266,81 +1211,6 @@ static void intel_i915_chipset_flush(struct agp_bridge_data *bridge) writel(1, intel_private.i9xx_flush_page); } -static int intel_i915_insert_entries(struct agp_memory *mem, off_t pg_start, - int type) -{ - int num_entries; - void *temp; - int ret = -EINVAL; - int mask_type; - - if (mem->page_count == 0) - goto out; - - temp = agp_bridge->current_size; - num_entries = A_SIZE_FIX(temp)->num_entries; - - if (pg_start < intel_private.base.gtt_stolen_entries) { - dev_printk(KERN_DEBUG, &intel_private.pcidev->dev, - "pg_start == 0x%.8lx, gtt_stolen_entries == 0x%.8x\n", - pg_start, intel_private.base.gtt_stolen_entries); - - dev_info(&intel_private.pcidev->dev, - "trying to insert into local/stolen memory\n"); - goto out_err; - } - - if ((pg_start + mem->page_count) > num_entries) - goto out_err; - - /* The i915 can't check the GTT for entries since it's read only; - * depend on the caller to make the correct offset decisions. - */ - - if (type != mem->type) - goto out_err; - - mask_type = agp_bridge->driver->agp_type_to_mask_type(agp_bridge, type); - - if (INTEL_GTT_GEN != 6 && mask_type != 0 && - mask_type != AGP_PHYS_MEMORY && - mask_type != INTEL_AGP_CACHED_MEMORY) - goto out_err; - - if (!mem->is_flushed) - global_cache_flush(); - - intel_agp_insert_sg_entries(mem, pg_start, mask_type); - - out: - ret = 0; - out_err: - mem->is_flushed = true; - return ret; -} - -static int intel_i915_remove_entries(struct agp_memory *mem, off_t pg_start, - int type) -{ - int i; - - if (mem->page_count == 0) - return 0; - - if (pg_start < intel_private.base.gtt_stolen_entries) { - dev_info(&intel_private.pcidev->dev, - "trying to disable local/stolen memory\n"); - return -EINVAL; - } - - for (i = pg_start; i < (mem->page_count + pg_start); i++) - writel(agp_bridge->scratch_page, intel_private.gtt+i); - - readl(intel_private.gtt+i-1); - - return 0; -} - static void i965_write_entry(dma_addr_t addr, unsigned int entry, unsigned int flags) { @@ -1349,6 +1219,11 @@ static void i965_write_entry(dma_addr_t addr, unsigned int entry, writel(addr | I810_PTE_VALID, intel_private.gtt + entry); } +static bool gen6_check_flags(unsigned int flags) +{ + return true; +} + static void gen6_write_entry(dma_addr_t addr, unsigned int entry, unsigned int flags) { @@ -1562,8 +1437,8 @@ static const struct agp_bridge_driver intel_gen6_driver = { .cache_flush = global_cache_flush, .create_gatt_table = intel_fake_agp_create_gatt_table, .free_gatt_table = intel_fake_agp_free_gatt_table, - .insert_memory = intel_i915_insert_entries, - .remove_memory = intel_i915_remove_entries, + .insert_memory = intel_fake_agp_insert_entries, + .remove_memory = intel_fake_agp_remove_entries, .alloc_by_type = intel_fake_agp_alloc_by_type, .free_by_type = intel_i810_free_by_type, .agp_alloc_page = agp_generic_alloc_page, @@ -1572,10 +1447,6 @@ static const struct agp_bridge_driver intel_gen6_driver = { .agp_destroy_pages = agp_generic_destroy_pages, .agp_type_to_mask_type = intel_gen6_type_to_mask_type, .chipset_flush = intel_i915_chipset_flush, -#if USE_PCI_DMA_API - .agp_map_memory = intel_agp_map_memory, - .agp_unmap_memory = intel_agp_unmap_memory, -#endif }; static const struct agp_bridge_driver intel_g33_driver = { @@ -1654,6 +1525,7 @@ static const struct intel_gtt_driver sandybridge_gtt_driver = { .gen = 6, .setup = i9xx_setup, .write_entry = gen6_write_entry, + .check_flags = gen6_check_flags, }; /* Table to describe Intel GMCH and AGP/PCIE GART drivers. At least one of -- cgit v1.1 From bdd30729b68d708c970125aab363931134698f2d Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Sun, 12 Sep 2010 12:34:44 +0200 Subject: intel-gtt: kill mask_memory functions That indirection mess can now go. Add a dummy i81x gtt_driver to avoid a NULL pointer check. Signed-off-by: Daniel Vetter Signed-off-by: Chris Wilson --- drivers/char/agp/intel-gtt.c | 105 ++++++------------------------------------- 1 file changed, 13 insertions(+), 92 deletions(-) diff --git a/drivers/char/agp/intel-gtt.c b/drivers/char/agp/intel-gtt.c index 44722c6..bb222d5 100644 --- a/drivers/char/agp/intel-gtt.c +++ b/drivers/char/agp/intel-gtt.c @@ -69,20 +69,6 @@ static struct gatt_mask intel_i810_masks[] = #define INTEL_AGP_CACHED_MEMORY_LLC_MLC 3 #define INTEL_AGP_CACHED_MEMORY_LLC_MLC_GFDT 4 -static struct gatt_mask intel_gen6_masks[] = -{ - {.mask = I810_PTE_VALID | GEN6_PTE_UNCACHED, - .type = INTEL_AGP_UNCACHED_MEMORY }, - {.mask = I810_PTE_VALID | GEN6_PTE_LLC, - .type = INTEL_AGP_CACHED_MEMORY_LLC }, - {.mask = I810_PTE_VALID | GEN6_PTE_LLC | GEN6_PTE_GFDT, - .type = INTEL_AGP_CACHED_MEMORY_LLC_GFDT }, - {.mask = I810_PTE_VALID | GEN6_PTE_LLC_MLC, - .type = INTEL_AGP_CACHED_MEMORY_LLC_MLC }, - {.mask = I810_PTE_VALID | GEN6_PTE_LLC_MLC | GEN6_PTE_GFDT, - .type = INTEL_AGP_CACHED_MEMORY_LLC_MLC_GFDT }, -}; - struct intel_gtt_driver { unsigned int gen : 8; unsigned int is_g33 : 1; @@ -287,34 +273,6 @@ static void i8xx_destroy_pages(struct page *page) atomic_dec(&agp_bridge->current_memory_agp); } -static int intel_i830_type_to_mask_type(struct agp_bridge_data *bridge, - int type) -{ - if (type < AGP_USER_TYPES) - return type; - else if (type == AGP_USER_CACHED_MEMORY) - return INTEL_AGP_CACHED_MEMORY; - else - return 0; -} - -static int intel_gen6_type_to_mask_type(struct agp_bridge_data *bridge, - int type) -{ - unsigned int type_mask = type & ~AGP_USER_CACHED_MEMORY_GFDT; - unsigned int gfdt = type & AGP_USER_CACHED_MEMORY_GFDT; - - if (type_mask == AGP_USER_UNCACHED_MEMORY) - return INTEL_AGP_UNCACHED_MEMORY; - else if (type_mask == AGP_USER_CACHED_MEMORY_LLC_MLC) - return gfdt ? INTEL_AGP_CACHED_MEMORY_LLC_MLC_GFDT : - INTEL_AGP_CACHED_MEMORY_LLC_MLC; - else /* set 'normal'/'cached' to LLC by default */ - return gfdt ? INTEL_AGP_CACHED_MEMORY_LLC_GFDT : - INTEL_AGP_CACHED_MEMORY_LLC; -} - - static int intel_i810_insert_entries(struct agp_memory *mem, off_t pg_start, int type) { @@ -1290,35 +1248,6 @@ static int i9xx_setup(void) return 0; } -/* - * The i965 supports 36-bit physical addresses, but to keep - * the format of the GTT the same, the bits that don't fit - * in a 32-bit word are shifted down to bits 4..7. - * - * Gcc is smart enough to notice that "(addr >> 28) & 0xf0" - * is always zero on 32-bit architectures, so no need to make - * this conditional. - */ -static unsigned long intel_i965_mask_memory(struct agp_bridge_data *bridge, - dma_addr_t addr, int type) -{ - /* Shift high bits down */ - addr |= (addr >> 28) & 0xf0; - - /* Type checking must be done elsewhere */ - return addr | bridge->driver->masks[type].mask; -} - -static unsigned long intel_gen6_mask_memory(struct agp_bridge_data *bridge, - dma_addr_t addr, int type) -{ - /* gen6 has bit11-4 for physical addr bit39-32 */ - addr |= (addr >> 28) & 0xff0; - - /* Type checking must be done elsewhere */ - return addr | bridge->driver->masks[type].mask; -} - static const struct agp_bridge_driver intel_810_driver = { .owner = THIS_MODULE, .aperture_sizes = intel_i810_sizes, @@ -1353,8 +1282,6 @@ static const struct agp_bridge_driver intel_830_driver = { .configure = intel_fake_agp_configure, .fetch_size = intel_fake_agp_fetch_size, .cleanup = intel_gtt_cleanup, - .mask_memory = intel_i810_mask_memory, - .masks = intel_i810_masks, .agp_enable = intel_fake_agp_enable, .cache_flush = global_cache_flush, .create_gatt_table = intel_fake_agp_create_gatt_table, @@ -1367,7 +1294,6 @@ static const struct agp_bridge_driver intel_830_driver = { .agp_alloc_pages = agp_generic_alloc_pages, .agp_destroy_page = agp_generic_destroy_page, .agp_destroy_pages = agp_generic_destroy_pages, - .agp_type_to_mask_type = intel_i830_type_to_mask_type, .chipset_flush = intel_i830_chipset_flush, }; @@ -1379,8 +1305,6 @@ static const struct agp_bridge_driver intel_915_driver = { .configure = intel_fake_agp_configure, .fetch_size = intel_fake_agp_fetch_size, .cleanup = intel_gtt_cleanup, - .mask_memory = intel_i810_mask_memory, - .masks = intel_i810_masks, .agp_enable = intel_fake_agp_enable, .cache_flush = global_cache_flush, .create_gatt_table = intel_fake_agp_create_gatt_table, @@ -1393,7 +1317,6 @@ static const struct agp_bridge_driver intel_915_driver = { .agp_alloc_pages = agp_generic_alloc_pages, .agp_destroy_page = agp_generic_destroy_page, .agp_destroy_pages = agp_generic_destroy_pages, - .agp_type_to_mask_type = intel_i830_type_to_mask_type, .chipset_flush = intel_i915_chipset_flush, }; @@ -1405,8 +1328,6 @@ static const struct agp_bridge_driver intel_i965_driver = { .configure = intel_fake_agp_configure, .fetch_size = intel_fake_agp_fetch_size, .cleanup = intel_gtt_cleanup, - .mask_memory = intel_i965_mask_memory, - .masks = intel_i810_masks, .agp_enable = intel_fake_agp_enable, .cache_flush = global_cache_flush, .create_gatt_table = intel_fake_agp_create_gatt_table, @@ -1419,7 +1340,6 @@ static const struct agp_bridge_driver intel_i965_driver = { .agp_alloc_pages = agp_generic_alloc_pages, .agp_destroy_page = agp_generic_destroy_page, .agp_destroy_pages = agp_generic_destroy_pages, - .agp_type_to_mask_type = intel_i830_type_to_mask_type, .chipset_flush = intel_i915_chipset_flush, }; @@ -1431,8 +1351,6 @@ static const struct agp_bridge_driver intel_gen6_driver = { .configure = intel_fake_agp_configure, .fetch_size = intel_fake_agp_fetch_size, .cleanup = intel_gtt_cleanup, - .mask_memory = intel_gen6_mask_memory, - .masks = intel_gen6_masks, .agp_enable = intel_fake_agp_enable, .cache_flush = global_cache_flush, .create_gatt_table = intel_fake_agp_create_gatt_table, @@ -1445,7 +1363,6 @@ static const struct agp_bridge_driver intel_gen6_driver = { .agp_alloc_pages = agp_generic_alloc_pages, .agp_destroy_page = agp_generic_destroy_page, .agp_destroy_pages = agp_generic_destroy_pages, - .agp_type_to_mask_type = intel_gen6_type_to_mask_type, .chipset_flush = intel_i915_chipset_flush, }; @@ -1457,8 +1374,6 @@ static const struct agp_bridge_driver intel_g33_driver = { .configure = intel_fake_agp_configure, .fetch_size = intel_fake_agp_fetch_size, .cleanup = intel_gtt_cleanup, - .mask_memory = intel_i965_mask_memory, - .masks = intel_i810_masks, .agp_enable = intel_fake_agp_enable, .cache_flush = global_cache_flush, .create_gatt_table = intel_fake_agp_create_gatt_table, @@ -1471,10 +1386,12 @@ static const struct agp_bridge_driver intel_g33_driver = { .agp_alloc_pages = agp_generic_alloc_pages, .agp_destroy_page = agp_generic_destroy_page, .agp_destroy_pages = agp_generic_destroy_pages, - .agp_type_to_mask_type = intel_i830_type_to_mask_type, .chipset_flush = intel_i915_chipset_flush, }; +static const struct intel_gtt_driver i81x_gtt_driver = { + .gen = 1, +}; static const struct intel_gtt_driver i8xx_gtt_driver = { .gen = 2, .setup = i830_setup, @@ -1538,10 +1455,14 @@ static const struct intel_gtt_driver_description { const struct agp_bridge_driver *gmch_driver; const struct intel_gtt_driver *gtt_driver; } intel_gtt_chipsets[] = { - { PCI_DEVICE_ID_INTEL_82810_IG1, "i810", &intel_810_driver , NULL}, - { PCI_DEVICE_ID_INTEL_82810_IG3, "i810", &intel_810_driver , NULL}, - { PCI_DEVICE_ID_INTEL_82810E_IG, "i810", &intel_810_driver , NULL}, - { PCI_DEVICE_ID_INTEL_82815_CGC, "i815", &intel_810_driver , NULL}, + { PCI_DEVICE_ID_INTEL_82810_IG1, "i810", &intel_810_driver, + &i81x_gtt_driver}, + { PCI_DEVICE_ID_INTEL_82810_IG3, "i810", &intel_810_driver, + &i81x_gtt_driver}, + { PCI_DEVICE_ID_INTEL_82810E_IG, "i810", &intel_810_driver, + &i81x_gtt_driver}, + { PCI_DEVICE_ID_INTEL_82815_CGC, "i815", &intel_810_driver, + &i81x_gtt_driver}, { PCI_DEVICE_ID_INTEL_82830_CGC, "830M", &intel_830_driver , &i8xx_gtt_driver}, { PCI_DEVICE_ID_INTEL_82845G_IG, "830M", @@ -1664,9 +1585,9 @@ int intel_gmch_probe(struct pci_dev *pdev, dev_info(&pdev->dev, "Intel %s Chipset\n", intel_gtt_chipsets[i].name); - if (bridge->driver->mask_memory == intel_gen6_mask_memory) + if (intel_private.driver->write_entry == gen6_write_entry) mask = 40; - else if (bridge->driver->mask_memory == intel_i965_mask_memory) + else if (intel_private.driver->write_entry == i965_write_entry) mask = 36; else mask = 32; -- cgit v1.1 From 1b263f246639c4777fbf6cfda932ecd1ea4bebb9 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Sun, 12 Sep 2010 00:27:24 +0200 Subject: intel-gtt: move chipset flush to the gtt driver struct This is the last differentiator between the different fake agp drivers. Signed-off-by: Daniel Vetter Signed-off-by: Chris Wilson --- drivers/char/agp/intel-gtt.c | 28 +++++++++++++++++++++------- 1 file changed, 21 insertions(+), 7 deletions(-) diff --git a/drivers/char/agp/intel-gtt.c b/drivers/char/agp/intel-gtt.c index bb222d5..abd422c 100644 --- a/drivers/char/agp/intel-gtt.c +++ b/drivers/char/agp/intel-gtt.c @@ -81,6 +81,7 @@ struct intel_gtt_driver { * For chipsets that need to support old ums (non-gem) code, this * needs to be identical to the various supported agp memory types! */ bool (*check_flags)(unsigned int flags); + void (*chipset_flush)(void); }; static struct _intel_private { @@ -838,7 +839,7 @@ static void intel_i830_setup_flush(void) * that buffer out, we just fill 1KB and clflush it out, on the assumption * that it'll push whatever was in there out. It appears to work. */ -static void intel_i830_chipset_flush(struct agp_bridge_data *bridge) +static void i830_chipset_flush(void) { unsigned int *pg = intel_private.i8xx_flush_page; @@ -1062,6 +1063,11 @@ static int intel_fake_agp_remove_entries(struct agp_memory *mem, return 0; } +static void intel_fake_agp_chipset_flush(struct agp_bridge_data *bridge) +{ + intel_private.driver->chipset_flush(); +} + static struct agp_memory *intel_fake_agp_alloc_by_type(size_t pg_count, int type) { @@ -1163,7 +1169,7 @@ static void intel_i9xx_setup_flush(void) "can't ioremap flush page - no chipset flushing\n"); } -static void intel_i915_chipset_flush(struct agp_bridge_data *bridge) +static void i9xx_chipset_flush(void) { if (intel_private.i9xx_flush_page) writel(1, intel_private.i9xx_flush_page); @@ -1294,7 +1300,7 @@ static const struct agp_bridge_driver intel_830_driver = { .agp_alloc_pages = agp_generic_alloc_pages, .agp_destroy_page = agp_generic_destroy_page, .agp_destroy_pages = agp_generic_destroy_pages, - .chipset_flush = intel_i830_chipset_flush, + .chipset_flush = intel_fake_agp_chipset_flush, }; static const struct agp_bridge_driver intel_915_driver = { @@ -1317,7 +1323,7 @@ static const struct agp_bridge_driver intel_915_driver = { .agp_alloc_pages = agp_generic_alloc_pages, .agp_destroy_page = agp_generic_destroy_page, .agp_destroy_pages = agp_generic_destroy_pages, - .chipset_flush = intel_i915_chipset_flush, + .chipset_flush = intel_fake_agp_chipset_flush, }; static const struct agp_bridge_driver intel_i965_driver = { @@ -1340,7 +1346,7 @@ static const struct agp_bridge_driver intel_i965_driver = { .agp_alloc_pages = agp_generic_alloc_pages, .agp_destroy_page = agp_generic_destroy_page, .agp_destroy_pages = agp_generic_destroy_pages, - .chipset_flush = intel_i915_chipset_flush, + .chipset_flush = intel_fake_agp_chipset_flush, }; static const struct agp_bridge_driver intel_gen6_driver = { @@ -1363,7 +1369,7 @@ static const struct agp_bridge_driver intel_gen6_driver = { .agp_alloc_pages = agp_generic_alloc_pages, .agp_destroy_page = agp_generic_destroy_page, .agp_destroy_pages = agp_generic_destroy_pages, - .chipset_flush = intel_i915_chipset_flush, + .chipset_flush = intel_fake_agp_chipset_flush, }; static const struct agp_bridge_driver intel_g33_driver = { @@ -1386,7 +1392,7 @@ static const struct agp_bridge_driver intel_g33_driver = { .agp_alloc_pages = agp_generic_alloc_pages, .agp_destroy_page = agp_generic_destroy_page, .agp_destroy_pages = agp_generic_destroy_pages, - .chipset_flush = intel_i915_chipset_flush, + .chipset_flush = intel_fake_agp_chipset_flush, }; static const struct intel_gtt_driver i81x_gtt_driver = { @@ -1397,6 +1403,7 @@ static const struct intel_gtt_driver i8xx_gtt_driver = { .setup = i830_setup, .write_entry = i830_write_entry, .check_flags = i830_check_flags, + .chipset_flush = i830_chipset_flush, }; static const struct intel_gtt_driver i915_gtt_driver = { .gen = 3, @@ -1404,6 +1411,7 @@ static const struct intel_gtt_driver i915_gtt_driver = { /* i945 is the last gpu to need phys mem (for overlay and cursors). */ .write_entry = i830_write_entry, .check_flags = i830_check_flags, + .chipset_flush = i9xx_chipset_flush, }; static const struct intel_gtt_driver g33_gtt_driver = { .gen = 3, @@ -1411,6 +1419,7 @@ static const struct intel_gtt_driver g33_gtt_driver = { .setup = i9xx_setup, .write_entry = i965_write_entry, .check_flags = i830_check_flags, + .chipset_flush = i9xx_chipset_flush, }; static const struct intel_gtt_driver pineview_gtt_driver = { .gen = 3, @@ -1418,18 +1427,21 @@ static const struct intel_gtt_driver pineview_gtt_driver = { .setup = i9xx_setup, .write_entry = i965_write_entry, .check_flags = i830_check_flags, + .chipset_flush = i9xx_chipset_flush, }; static const struct intel_gtt_driver i965_gtt_driver = { .gen = 4, .setup = i9xx_setup, .write_entry = i965_write_entry, .check_flags = i830_check_flags, + .chipset_flush = i9xx_chipset_flush, }; static const struct intel_gtt_driver g4x_gtt_driver = { .gen = 5, .setup = i9xx_setup, .write_entry = i965_write_entry, .check_flags = i830_check_flags, + .chipset_flush = i9xx_chipset_flush, }; static const struct intel_gtt_driver ironlake_gtt_driver = { .gen = 5, @@ -1437,12 +1449,14 @@ static const struct intel_gtt_driver ironlake_gtt_driver = { .setup = i9xx_setup, .write_entry = i965_write_entry, .check_flags = i830_check_flags, + .chipset_flush = i9xx_chipset_flush, }; static const struct intel_gtt_driver sandybridge_gtt_driver = { .gen = 6, .setup = i9xx_setup, .write_entry = gen6_write_entry, .check_flags = gen6_check_flags, + .chipset_flush = i9xx_chipset_flush, }; /* Table to describe Intel GMCH and AGP/PCIE GART drivers. At least one of -- cgit v1.1 From e9b1cc81c2222108d866323c51f482dd6db8d689 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Sun, 12 Sep 2010 00:29:26 +0200 Subject: intel-gtt: consolidate fake_agp driver structs They're now all the same. Signed-off-by: Daniel Vetter Signed-off-by: Chris Wilson --- drivers/char/agp/intel-gtt.c | 170 ++++++++++--------------------------------- 1 file changed, 39 insertions(+), 131 deletions(-) diff --git a/drivers/char/agp/intel-gtt.c b/drivers/char/agp/intel-gtt.c index abd422c..57dc504 100644 --- a/drivers/char/agp/intel-gtt.c +++ b/drivers/char/agp/intel-gtt.c @@ -1280,99 +1280,7 @@ static const struct agp_bridge_driver intel_810_driver = { .agp_type_to_mask_type = agp_generic_type_to_mask_type, }; -static const struct agp_bridge_driver intel_830_driver = { - .owner = THIS_MODULE, - .size_type = FIXED_APER_SIZE, - .aperture_sizes = intel_fake_agp_sizes, - .num_aperture_sizes = ARRAY_SIZE(intel_fake_agp_sizes), - .configure = intel_fake_agp_configure, - .fetch_size = intel_fake_agp_fetch_size, - .cleanup = intel_gtt_cleanup, - .agp_enable = intel_fake_agp_enable, - .cache_flush = global_cache_flush, - .create_gatt_table = intel_fake_agp_create_gatt_table, - .free_gatt_table = intel_fake_agp_free_gatt_table, - .insert_memory = intel_fake_agp_insert_entries, - .remove_memory = intel_fake_agp_remove_entries, - .alloc_by_type = intel_fake_agp_alloc_by_type, - .free_by_type = intel_i810_free_by_type, - .agp_alloc_page = agp_generic_alloc_page, - .agp_alloc_pages = agp_generic_alloc_pages, - .agp_destroy_page = agp_generic_destroy_page, - .agp_destroy_pages = agp_generic_destroy_pages, - .chipset_flush = intel_fake_agp_chipset_flush, -}; - -static const struct agp_bridge_driver intel_915_driver = { - .owner = THIS_MODULE, - .size_type = FIXED_APER_SIZE, - .aperture_sizes = intel_fake_agp_sizes, - .num_aperture_sizes = ARRAY_SIZE(intel_fake_agp_sizes), - .configure = intel_fake_agp_configure, - .fetch_size = intel_fake_agp_fetch_size, - .cleanup = intel_gtt_cleanup, - .agp_enable = intel_fake_agp_enable, - .cache_flush = global_cache_flush, - .create_gatt_table = intel_fake_agp_create_gatt_table, - .free_gatt_table = intel_fake_agp_free_gatt_table, - .insert_memory = intel_fake_agp_insert_entries, - .remove_memory = intel_fake_agp_remove_entries, - .alloc_by_type = intel_fake_agp_alloc_by_type, - .free_by_type = intel_i810_free_by_type, - .agp_alloc_page = agp_generic_alloc_page, - .agp_alloc_pages = agp_generic_alloc_pages, - .agp_destroy_page = agp_generic_destroy_page, - .agp_destroy_pages = agp_generic_destroy_pages, - .chipset_flush = intel_fake_agp_chipset_flush, -}; - -static const struct agp_bridge_driver intel_i965_driver = { - .owner = THIS_MODULE, - .size_type = FIXED_APER_SIZE, - .aperture_sizes = intel_fake_agp_sizes, - .num_aperture_sizes = ARRAY_SIZE(intel_fake_agp_sizes), - .configure = intel_fake_agp_configure, - .fetch_size = intel_fake_agp_fetch_size, - .cleanup = intel_gtt_cleanup, - .agp_enable = intel_fake_agp_enable, - .cache_flush = global_cache_flush, - .create_gatt_table = intel_fake_agp_create_gatt_table, - .free_gatt_table = intel_fake_agp_free_gatt_table, - .insert_memory = intel_fake_agp_insert_entries, - .remove_memory = intel_fake_agp_remove_entries, - .alloc_by_type = intel_fake_agp_alloc_by_type, - .free_by_type = intel_i810_free_by_type, - .agp_alloc_page = agp_generic_alloc_page, - .agp_alloc_pages = agp_generic_alloc_pages, - .agp_destroy_page = agp_generic_destroy_page, - .agp_destroy_pages = agp_generic_destroy_pages, - .chipset_flush = intel_fake_agp_chipset_flush, -}; - -static const struct agp_bridge_driver intel_gen6_driver = { - .owner = THIS_MODULE, - .size_type = FIXED_APER_SIZE, - .aperture_sizes = intel_fake_agp_sizes, - .num_aperture_sizes = ARRAY_SIZE(intel_fake_agp_sizes), - .configure = intel_fake_agp_configure, - .fetch_size = intel_fake_agp_fetch_size, - .cleanup = intel_gtt_cleanup, - .agp_enable = intel_fake_agp_enable, - .cache_flush = global_cache_flush, - .create_gatt_table = intel_fake_agp_create_gatt_table, - .free_gatt_table = intel_fake_agp_free_gatt_table, - .insert_memory = intel_fake_agp_insert_entries, - .remove_memory = intel_fake_agp_remove_entries, - .alloc_by_type = intel_fake_agp_alloc_by_type, - .free_by_type = intel_i810_free_by_type, - .agp_alloc_page = agp_generic_alloc_page, - .agp_alloc_pages = agp_generic_alloc_pages, - .agp_destroy_page = agp_generic_destroy_page, - .agp_destroy_pages = agp_generic_destroy_pages, - .chipset_flush = intel_fake_agp_chipset_flush, -}; - -static const struct agp_bridge_driver intel_g33_driver = { +static const struct agp_bridge_driver intel_fake_agp_driver = { .owner = THIS_MODULE, .size_type = FIXED_APER_SIZE, .aperture_sizes = intel_fake_agp_sizes, @@ -1478,81 +1386,81 @@ static const struct intel_gtt_driver_description { { PCI_DEVICE_ID_INTEL_82815_CGC, "i815", &intel_810_driver, &i81x_gtt_driver}, { PCI_DEVICE_ID_INTEL_82830_CGC, "830M", - &intel_830_driver , &i8xx_gtt_driver}, + &intel_fake_agp_driver, &i8xx_gtt_driver}, { PCI_DEVICE_ID_INTEL_82845G_IG, "830M", - &intel_830_driver , &i8xx_gtt_driver}, + &intel_fake_agp_driver, &i8xx_gtt_driver}, { PCI_DEVICE_ID_INTEL_82854_IG, "854", - &intel_830_driver , &i8xx_gtt_driver}, + &intel_fake_agp_driver, &i8xx_gtt_driver}, { PCI_DEVICE_ID_INTEL_82855GM_IG, "855GM", - &intel_830_driver , &i8xx_gtt_driver}, + &intel_fake_agp_driver, &i8xx_gtt_driver}, { PCI_DEVICE_ID_INTEL_82865_IG, "865", - &intel_830_driver , &i8xx_gtt_driver}, + &intel_fake_agp_driver, &i8xx_gtt_driver}, { PCI_DEVICE_ID_INTEL_E7221_IG, "E7221 (i915)", - &intel_915_driver , &i915_gtt_driver }, + &intel_fake_agp_driver, &i915_gtt_driver }, { PCI_DEVICE_ID_INTEL_82915G_IG, "915G", - &intel_915_driver , &i915_gtt_driver }, + &intel_fake_agp_driver, &i915_gtt_driver }, { PCI_DEVICE_ID_INTEL_82915GM_IG, "915GM", - &intel_915_driver , &i915_gtt_driver }, + &intel_fake_agp_driver, &i915_gtt_driver }, { PCI_DEVICE_ID_INTEL_82945G_IG, "945G", - &intel_915_driver , &i915_gtt_driver }, + &intel_fake_agp_driver, &i915_gtt_driver }, { PCI_DEVICE_ID_INTEL_82945GM_IG, "945GM", - &intel_915_driver , &i915_gtt_driver }, + &intel_fake_agp_driver, &i915_gtt_driver }, { PCI_DEVICE_ID_INTEL_82945GME_IG, "945GME", - &intel_915_driver , &i915_gtt_driver }, + &intel_fake_agp_driver, &i915_gtt_driver }, { PCI_DEVICE_ID_INTEL_82946GZ_IG, "946GZ", - &intel_i965_driver , &i965_gtt_driver }, + &intel_fake_agp_driver, &i965_gtt_driver }, { PCI_DEVICE_ID_INTEL_82G35_IG, "G35", - &intel_i965_driver , &i965_gtt_driver }, + &intel_fake_agp_driver, &i965_gtt_driver }, { PCI_DEVICE_ID_INTEL_82965Q_IG, "965Q", - &intel_i965_driver , &i965_gtt_driver }, + &intel_fake_agp_driver, &i965_gtt_driver }, { PCI_DEVICE_ID_INTEL_82965G_IG, "965G", - &intel_i965_driver , &i965_gtt_driver }, + &intel_fake_agp_driver, &i965_gtt_driver }, { PCI_DEVICE_ID_INTEL_82965GM_IG, "965GM", - &intel_i965_driver , &i965_gtt_driver }, + &intel_fake_agp_driver, &i965_gtt_driver }, { PCI_DEVICE_ID_INTEL_82965GME_IG, "965GME/GLE", - &intel_i965_driver , &i965_gtt_driver }, + &intel_fake_agp_driver, &i965_gtt_driver }, { PCI_DEVICE_ID_INTEL_G33_IG, "G33", - &intel_g33_driver , &g33_gtt_driver }, + &intel_fake_agp_driver, &g33_gtt_driver }, { PCI_DEVICE_ID_INTEL_Q35_IG, "Q35", - &intel_g33_driver , &g33_gtt_driver }, + &intel_fake_agp_driver, &g33_gtt_driver }, { PCI_DEVICE_ID_INTEL_Q33_IG, "Q33", - &intel_g33_driver , &g33_gtt_driver }, + &intel_fake_agp_driver, &g33_gtt_driver }, { PCI_DEVICE_ID_INTEL_PINEVIEW_M_IG, "GMA3150", - &intel_g33_driver , &pineview_gtt_driver }, + &intel_fake_agp_driver, &pineview_gtt_driver }, { PCI_DEVICE_ID_INTEL_PINEVIEW_IG, "GMA3150", - &intel_g33_driver , &pineview_gtt_driver }, + &intel_fake_agp_driver, &pineview_gtt_driver }, { PCI_DEVICE_ID_INTEL_GM45_IG, "GM45", - &intel_i965_driver , &g4x_gtt_driver }, + &intel_fake_agp_driver, &g4x_gtt_driver }, { PCI_DEVICE_ID_INTEL_EAGLELAKE_IG, "Eaglelake", - &intel_i965_driver , &g4x_gtt_driver }, + &intel_fake_agp_driver, &g4x_gtt_driver }, { PCI_DEVICE_ID_INTEL_Q45_IG, "Q45/Q43", - &intel_i965_driver , &g4x_gtt_driver }, + &intel_fake_agp_driver, &g4x_gtt_driver }, { PCI_DEVICE_ID_INTEL_G45_IG, "G45/G43", - &intel_i965_driver , &g4x_gtt_driver }, + &intel_fake_agp_driver, &g4x_gtt_driver }, { PCI_DEVICE_ID_INTEL_B43_IG, "B43", - &intel_i965_driver , &g4x_gtt_driver }, + &intel_fake_agp_driver, &g4x_gtt_driver }, { PCI_DEVICE_ID_INTEL_B43_1_IG, "B43", - &intel_i965_driver , &g4x_gtt_driver }, + &intel_fake_agp_driver, &g4x_gtt_driver }, { PCI_DEVICE_ID_INTEL_G41_IG, "G41", - &intel_i965_driver , &g4x_gtt_driver }, + &intel_fake_agp_driver, &g4x_gtt_driver }, { PCI_DEVICE_ID_INTEL_IRONLAKE_D_IG, - "HD Graphics", &intel_i965_driver , &ironlake_gtt_driver }, + "HD Graphics", &intel_fake_agp_driver, &ironlake_gtt_driver }, { PCI_DEVICE_ID_INTEL_IRONLAKE_M_IG, - "HD Graphics", &intel_i965_driver , &ironlake_gtt_driver }, + "HD Graphics", &intel_fake_agp_driver, &ironlake_gtt_driver }, { PCI_DEVICE_ID_INTEL_SANDYBRIDGE_GT1_IG, - "Sandybridge", &intel_gen6_driver , &sandybridge_gtt_driver }, + "Sandybridge", &intel_fake_agp_driver, &sandybridge_gtt_driver }, { PCI_DEVICE_ID_INTEL_SANDYBRIDGE_GT2_IG, - "Sandybridge", &intel_gen6_driver , &sandybridge_gtt_driver }, + "Sandybridge", &intel_fake_agp_driver, &sandybridge_gtt_driver }, { PCI_DEVICE_ID_INTEL_SANDYBRIDGE_GT2_PLUS_IG, - "Sandybridge", &intel_gen6_driver , &sandybridge_gtt_driver }, + "Sandybridge", &intel_fake_agp_driver, &sandybridge_gtt_driver }, { PCI_DEVICE_ID_INTEL_SANDYBRIDGE_M_GT1_IG, - "Sandybridge", &intel_gen6_driver , &sandybridge_gtt_driver }, + "Sandybridge", &intel_fake_agp_driver, &sandybridge_gtt_driver }, { PCI_DEVICE_ID_INTEL_SANDYBRIDGE_M_GT2_IG, - "Sandybridge", &intel_gen6_driver , &sandybridge_gtt_driver }, + "Sandybridge", &intel_fake_agp_driver, &sandybridge_gtt_driver }, { PCI_DEVICE_ID_INTEL_SANDYBRIDGE_M_GT2_PLUS_IG, - "Sandybridge", &intel_gen6_driver , &sandybridge_gtt_driver }, + "Sandybridge", &intel_fake_agp_driver, &sandybridge_gtt_driver }, { PCI_DEVICE_ID_INTEL_SANDYBRIDGE_S_IG, - "Sandybridge", &intel_gen6_driver , &sandybridge_gtt_driver }, + "Sandybridge", &intel_fake_agp_driver, &sandybridge_gtt_driver }, { 0, NULL, NULL } }; -- cgit v1.1 From aaa62591199162e6496b4f47cac4f5923bc571d1 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Sun, 12 Sep 2010 11:07:15 +0200 Subject: agp: kill agp_(unmap|map)_memory DMA remapping was only used by the intel-gtt driver. With that code now folded into the driver, kill the agp generic support for it. Cc: Dave Airlie Signed-off-by: Daniel Vetter Signed-off-by: Chris Wilson --- drivers/char/agp/agp.h | 3 --- drivers/char/agp/generic.c | 8 -------- 2 files changed, 11 deletions(-) diff --git a/drivers/char/agp/agp.h b/drivers/char/agp/agp.h index 04ad0bb..5259065 100644 --- a/drivers/char/agp/agp.h +++ b/drivers/char/agp/agp.h @@ -121,9 +121,6 @@ struct agp_bridge_driver { void (*agp_destroy_pages)(struct agp_memory *); int (*agp_type_to_mask_type) (struct agp_bridge_data *, int); void (*chipset_flush)(struct agp_bridge_data *); - - int (*agp_map_memory)(struct agp_memory *mem); - void (*agp_unmap_memory)(struct agp_memory *mem); }; struct agp_bridge_data { diff --git a/drivers/char/agp/generic.c b/drivers/char/agp/generic.c index d2abf51..78235ce 100644 --- a/drivers/char/agp/generic.c +++ b/drivers/char/agp/generic.c @@ -437,11 +437,6 @@ int agp_bind_memory(struct agp_memory *curr, off_t pg_start) curr->is_flushed = true; } - if (curr->bridge->driver->agp_map_memory) { - ret_val = curr->bridge->driver->agp_map_memory(curr); - if (ret_val) - return ret_val; - } ret_val = curr->bridge->driver->insert_memory(curr, pg_start, curr->type); if (ret_val != 0) @@ -483,9 +478,6 @@ int agp_unbind_memory(struct agp_memory *curr) if (ret_val != 0) return ret_val; - if (curr->bridge->driver->agp_unmap_memory) - curr->bridge->driver->agp_unmap_memory(curr); - curr->is_bound = false; curr->pg_start = 0; spin_lock(&curr->bridge->mapped_lock); -- cgit v1.1 From 0af9e92e779602bdd6d4d19acf63b4802fab91b6 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Sun, 12 Sep 2010 14:04:03 +0200 Subject: intel-gtt: clean up gtt size reporting Consolidate everything in intel-gtt.c and also kill the export of intel_max_stolen. Signed-off-by: Daniel Vetter Signed-off-by: Chris Wilson --- drivers/char/agp/intel-gtt.c | 6 +++++- drivers/gpu/drm/i915/i915_dma.c | 1 - include/drm/intel-gtt.h | 2 -- 3 files changed, 5 insertions(+), 4 deletions(-) diff --git a/drivers/char/agp/intel-gtt.c b/drivers/char/agp/intel-gtt.c index 57dc504..4f84063 100644 --- a/drivers/char/agp/intel-gtt.c +++ b/drivers/char/agp/intel-gtt.c @@ -41,7 +41,6 @@ /* Max amount of stolen space, anything above will be returned to Linux */ int intel_max_stolen = 32 * 1024 * 1024; -EXPORT_SYMBOL(intel_max_stolen); static const struct aper_size_info_fixed intel_i810_sizes[] = { @@ -756,6 +755,11 @@ static int intel_gtt_init(void) intel_private.base.gtt_mappable_entries = intel_gtt_mappable_entries(); intel_private.base.gtt_total_entries = intel_gtt_total_entries(); + dev_info(&intel_private.bridge_dev->dev, + "detected gtt size: %dK total, %dK mappable\n", + intel_private.base.gtt_total_entries * 4, + intel_private.base.gtt_mappable_entries * 4); + gtt_map_size = intel_private.base.gtt_total_entries * 4; intel_private.gtt = ioremap(intel_private.gtt_bus_addr, diff --git a/drivers/gpu/drm/i915/i915_dma.c b/drivers/gpu/drm/i915/i915_dma.c index 9977a0a..dd7a0de 100644 --- a/drivers/gpu/drm/i915/i915_dma.c +++ b/drivers/gpu/drm/i915/i915_dma.c @@ -1200,7 +1200,6 @@ static int i915_load_modeset_init(struct drm_device *dev, /* Basic memrange allocator for stolen space (aka mm.vram) */ drm_mm_init(&dev_priv->mm.vram, 0, prealloc_size); - DRM_INFO("set up %ldM of stolen space\n", prealloc_size / (1024*1024)); /* We're off and running w/KMS */ dev_priv->mm.suspended = 0; diff --git a/include/drm/intel-gtt.h b/include/drm/intel-gtt.h index b3aa7ab..d3c81946 100644 --- a/include/drm/intel-gtt.h +++ b/include/drm/intel-gtt.h @@ -2,8 +2,6 @@ #ifndef _DRM_INTEL_GTT_H #define _DRM_INTEL_GTT_H -extern int intel_max_stolen; /* from AGP driver */ - struct intel_gtt { /* Number of stolen gtt entries at the beginning. */ unsigned int gtt_stolen_entries; -- cgit v1.1 From 22533b494ff6a812b3e97248cc6c062858396182 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Sun, 12 Sep 2010 16:38:55 +0200 Subject: intel-gtt: store the dma mask size in intel_gtt_driver Storing this explicitly makes for clearer code and hopefully less further confusion. Signed-off-by: Daniel Vetter Signed-off-by: Chris Wilson --- drivers/char/agp/intel-gtt.c | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/drivers/char/agp/intel-gtt.c b/drivers/char/agp/intel-gtt.c index 4f84063..f82a2a6 100644 --- a/drivers/char/agp/intel-gtt.c +++ b/drivers/char/agp/intel-gtt.c @@ -73,6 +73,7 @@ struct intel_gtt_driver { unsigned int is_g33 : 1; unsigned int is_pineview : 1; unsigned int is_ironlake : 1; + unsigned int dma_mask_size : 8; /* Chipset specific GTT setup */ int (*setup)(void); void (*write_entry)(dma_addr_t addr, unsigned int entry, unsigned int flags); @@ -1309,11 +1310,13 @@ static const struct agp_bridge_driver intel_fake_agp_driver = { static const struct intel_gtt_driver i81x_gtt_driver = { .gen = 1, + .dma_mask_size = 32, }; static const struct intel_gtt_driver i8xx_gtt_driver = { .gen = 2, .setup = i830_setup, .write_entry = i830_write_entry, + .dma_mask_size = 32, .check_flags = i830_check_flags, .chipset_flush = i830_chipset_flush, }; @@ -1322,6 +1325,7 @@ static const struct intel_gtt_driver i915_gtt_driver = { .setup = i9xx_setup, /* i945 is the last gpu to need phys mem (for overlay and cursors). */ .write_entry = i830_write_entry, + .dma_mask_size = 32, .check_flags = i830_check_flags, .chipset_flush = i9xx_chipset_flush, }; @@ -1330,6 +1334,7 @@ static const struct intel_gtt_driver g33_gtt_driver = { .is_g33 = 1, .setup = i9xx_setup, .write_entry = i965_write_entry, + .dma_mask_size = 36, .check_flags = i830_check_flags, .chipset_flush = i9xx_chipset_flush, }; @@ -1338,6 +1343,7 @@ static const struct intel_gtt_driver pineview_gtt_driver = { .is_pineview = 1, .is_g33 = 1, .setup = i9xx_setup, .write_entry = i965_write_entry, + .dma_mask_size = 36, .check_flags = i830_check_flags, .chipset_flush = i9xx_chipset_flush, }; @@ -1345,6 +1351,7 @@ static const struct intel_gtt_driver i965_gtt_driver = { .gen = 4, .setup = i9xx_setup, .write_entry = i965_write_entry, + .dma_mask_size = 36, .check_flags = i830_check_flags, .chipset_flush = i9xx_chipset_flush, }; @@ -1352,6 +1359,7 @@ static const struct intel_gtt_driver g4x_gtt_driver = { .gen = 5, .setup = i9xx_setup, .write_entry = i965_write_entry, + .dma_mask_size = 36, .check_flags = i830_check_flags, .chipset_flush = i9xx_chipset_flush, }; @@ -1360,6 +1368,7 @@ static const struct intel_gtt_driver ironlake_gtt_driver = { .is_ironlake = 1, .setup = i9xx_setup, .write_entry = i965_write_entry, + .dma_mask_size = 36, .check_flags = i830_check_flags, .chipset_flush = i9xx_chipset_flush, }; @@ -1367,6 +1376,7 @@ static const struct intel_gtt_driver sandybridge_gtt_driver = { .gen = 6, .setup = i9xx_setup, .write_entry = gen6_write_entry, + .dma_mask_size = 40, .check_flags = gen6_check_flags, .chipset_flush = i9xx_chipset_flush, }; @@ -1511,13 +1521,7 @@ int intel_gmch_probe(struct pci_dev *pdev, dev_info(&pdev->dev, "Intel %s Chipset\n", intel_gtt_chipsets[i].name); - if (intel_private.driver->write_entry == gen6_write_entry) - mask = 40; - else if (intel_private.driver->write_entry == i965_write_entry) - mask = 36; - else - mask = 32; - + mask = intel_private.driver->dma_mask_size; if (pci_set_dma_mask(intel_private.pcidev, DMA_BIT_MASK(mask))) dev_err(&intel_private.pcidev->dev, "set gfx device dma mask %d-bit failed!\n", mask); -- cgit v1.1 From ae83dd5c7d80e0f9063739a18e270da7207a91e3 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Sun, 12 Sep 2010 17:11:15 +0200 Subject: intel-gtt add a cleanup function for chipset specific stuff The old code didn't clean up the i830 chipset flush page. And it looks nicer. Signed-off-by: Daniel Vetter Signed-off-by: Chris Wilson --- drivers/char/agp/intel-gtt.c | 39 +++++++++++++++++++++++++++++++-------- 1 file changed, 31 insertions(+), 8 deletions(-) diff --git a/drivers/char/agp/intel-gtt.c b/drivers/char/agp/intel-gtt.c index f82a2a6..9a03815 100644 --- a/drivers/char/agp/intel-gtt.c +++ b/drivers/char/agp/intel-gtt.c @@ -76,6 +76,9 @@ struct intel_gtt_driver { unsigned int dma_mask_size : 8; /* Chipset specific GTT setup */ int (*setup)(void); + /* This should undo anything done in ->setup() save the unmapping + * of the mmio register file, that's done in the generic code. */ + void (*cleanup)(void); void (*write_entry)(dma_addr_t addr, unsigned int entry, unsigned int flags); /* Flags is a more or less chipset specific opaque value. * For chipsets that need to support old ums (non-gem) code, this @@ -732,12 +735,8 @@ static void intel_gtt_teardown_scratch_page(void) static void intel_gtt_cleanup(void) { - if (intel_private.i9xx_flush_page) - iounmap(intel_private.i9xx_flush_page); - if (intel_private.resource_valid) - release_resource(&intel_private.ifp_resource); - intel_private.ifp_resource.start = 0; - intel_private.resource_valid = 0; + intel_private.driver->cleanup(); + iounmap(intel_private.gtt); iounmap(intel_private.registers); @@ -766,6 +765,7 @@ static int intel_gtt_init(void) intel_private.gtt = ioremap(intel_private.gtt_bus_addr, gtt_map_size); if (!intel_private.gtt) { + intel_private.driver->cleanup(); iounmap(intel_private.registers); return -ENOMEM; } @@ -775,6 +775,7 @@ static int intel_gtt_init(void) /* we have to call this as early as possible after the MMIO base address is known */ intel_private.base.gtt_stolen_entries = intel_gtt_stolen_entries(); if (intel_private.base.gtt_stolen_entries == 0) { + intel_private.driver->cleanup(); iounmap(intel_private.registers); iounmap(intel_private.gtt); return -ENOMEM; @@ -809,7 +810,7 @@ static int intel_fake_agp_fetch_size(void) return 0; } -static void intel_i830_fini_flush(void) +static void i830_cleanup(void) { kunmap(intel_private.i8xx_page); intel_private.i8xx_flush_page = NULL; @@ -831,7 +832,7 @@ static void intel_i830_setup_flush(void) intel_private.i8xx_flush_page = kmap(intel_private.i8xx_page); if (!intel_private.i8xx_flush_page) - intel_i830_fini_flush(); + i830_cleanup(); } /* The chipset_flush interface needs to get data that has already been @@ -1174,6 +1175,16 @@ static void intel_i9xx_setup_flush(void) "can't ioremap flush page - no chipset flushing\n"); } +static void i9xx_cleanup(void) +{ + if (intel_private.i9xx_flush_page) + iounmap(intel_private.i9xx_flush_page); + if (intel_private.resource_valid) + release_resource(&intel_private.ifp_resource); + intel_private.ifp_resource.start = 0; + intel_private.resource_valid = 0; +} + static void i9xx_chipset_flush(void) { if (intel_private.i9xx_flush_page) @@ -1217,6 +1228,10 @@ static void gen6_write_entry(dma_addr_t addr, unsigned int entry, writel(addr | pte_flags, intel_private.gtt + entry); } +static void gen6_cleanup(void) +{ +} + static int i9xx_setup(void) { u32 reg_addr; @@ -1315,6 +1330,7 @@ static const struct intel_gtt_driver i81x_gtt_driver = { static const struct intel_gtt_driver i8xx_gtt_driver = { .gen = 2, .setup = i830_setup, + .cleanup = i830_cleanup, .write_entry = i830_write_entry, .dma_mask_size = 32, .check_flags = i830_check_flags, @@ -1323,6 +1339,7 @@ static const struct intel_gtt_driver i8xx_gtt_driver = { static const struct intel_gtt_driver i915_gtt_driver = { .gen = 3, .setup = i9xx_setup, + .cleanup = i9xx_cleanup, /* i945 is the last gpu to need phys mem (for overlay and cursors). */ .write_entry = i830_write_entry, .dma_mask_size = 32, @@ -1333,6 +1350,7 @@ static const struct intel_gtt_driver g33_gtt_driver = { .gen = 3, .is_g33 = 1, .setup = i9xx_setup, + .cleanup = i9xx_cleanup, .write_entry = i965_write_entry, .dma_mask_size = 36, .check_flags = i830_check_flags, @@ -1342,6 +1360,7 @@ static const struct intel_gtt_driver pineview_gtt_driver = { .gen = 3, .is_pineview = 1, .is_g33 = 1, .setup = i9xx_setup, + .cleanup = i9xx_cleanup, .write_entry = i965_write_entry, .dma_mask_size = 36, .check_flags = i830_check_flags, @@ -1350,6 +1369,7 @@ static const struct intel_gtt_driver pineview_gtt_driver = { static const struct intel_gtt_driver i965_gtt_driver = { .gen = 4, .setup = i9xx_setup, + .cleanup = i9xx_cleanup, .write_entry = i965_write_entry, .dma_mask_size = 36, .check_flags = i830_check_flags, @@ -1358,6 +1378,7 @@ static const struct intel_gtt_driver i965_gtt_driver = { static const struct intel_gtt_driver g4x_gtt_driver = { .gen = 5, .setup = i9xx_setup, + .cleanup = i9xx_cleanup, .write_entry = i965_write_entry, .dma_mask_size = 36, .check_flags = i830_check_flags, @@ -1367,6 +1388,7 @@ static const struct intel_gtt_driver ironlake_gtt_driver = { .gen = 5, .is_ironlake = 1, .setup = i9xx_setup, + .cleanup = i9xx_cleanup, .write_entry = i965_write_entry, .dma_mask_size = 36, .check_flags = i830_check_flags, @@ -1375,6 +1397,7 @@ static const struct intel_gtt_driver ironlake_gtt_driver = { static const struct intel_gtt_driver sandybridge_gtt_driver = { .gen = 6, .setup = i9xx_setup, + .cleanup = gen6_cleanup, .write_entry = gen6_write_entry, .dma_mask_size = 40, .check_flags = gen6_check_flags, -- cgit v1.1 From 6eecba33f2fc24544073631dc1b23b7a312e644b Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Wed, 8 Sep 2010 09:45:11 +0100 Subject: drm/i915: Disable output polling across suspend & resume Suspending (especially hibernating) may take a finite amount of time, during which a hotplug event may trigger and we will attempt to handle it with inconsistent state. Disable hotplug polling around suspend and resume. Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=30070 Reported-by: Rui Tiago Matos Signed-off-by: Chris Wilson --- drivers/gpu/drm/i915/i915_dma.c | 2 -- drivers/gpu/drm/i915/i915_drv.c | 11 ++++++++++- 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_dma.c b/drivers/gpu/drm/i915/i915_dma.c index dd7a0de..048c54b 100644 --- a/drivers/gpu/drm/i915/i915_dma.c +++ b/drivers/gpu/drm/i915/i915_dma.c @@ -1172,10 +1172,8 @@ static void i915_switcheroo_set_state(struct pci_dev *pdev, enum vga_switcheroo_ /* i915 resume handler doesn't set to D0 */ pci_set_power_state(dev->pdev, PCI_D0); i915_resume(dev); - drm_kms_helper_poll_enable(dev); } else { printk(KERN_ERR "i915: switched off\n"); - drm_kms_helper_poll_disable(dev); i915_suspend(dev, pmm); } } diff --git a/drivers/gpu/drm/i915/i915_drv.c b/drivers/gpu/drm/i915/i915_drv.c index 2c87f9b..4e83bb3 100644 --- a/drivers/gpu/drm/i915/i915_drv.c +++ b/drivers/gpu/drm/i915/i915_drv.c @@ -281,6 +281,8 @@ int i915_suspend(struct drm_device *dev, pm_message_t state) if (state.event == PM_EVENT_PRETHAW) return 0; + drm_kms_helper_poll_disable(dev); + error = i915_drm_freeze(dev); if (error) return error; @@ -325,12 +327,19 @@ static int i915_drm_thaw(struct drm_device *dev) int i915_resume(struct drm_device *dev) { + int ret; + if (pci_enable_device(dev->pdev)) return -EIO; pci_set_master(dev->pdev); - return i915_drm_thaw(dev); + ret = i915_drm_thaw(dev); + if (ret) + return ret; + + drm_kms_helper_poll_enable(dev); + return 0; } static int i965_reset_complete(struct drm_device *dev) -- cgit v1.1 From cdd59983118c02d9c5ba0c116ded1faef47ec452 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Wed, 8 Sep 2010 16:30:16 +0100 Subject: drm/i915: Drop crtc->fb pin on disable. In order to handle disable_functions() where the framebuffer is decoupled from the crtc we need to unpin the fb in order to prevent a leak. Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=29857 Reported-by: Sitsofe Wheeler Signed-off-by: Chris Wilson --- drivers/gpu/drm/i915/intel_display.c | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 461bf48..e6f7ebf 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -2487,6 +2487,20 @@ static void intel_crtc_dpms(struct drm_crtc *crtc, int mode) } } +static void intel_crtc_disable(struct drm_crtc *crtc) +{ + struct drm_crtc_helper_funcs *crtc_funcs = crtc->helper_private; + struct drm_device *dev = crtc->dev; + + crtc_funcs->dpms(crtc, DRM_MODE_DPMS_OFF); + + if (crtc->fb) { + mutex_lock(&dev->struct_mutex); + i915_gem_object_unpin(to_intel_framebuffer(crtc->fb)->obj); + mutex_unlock(&dev->struct_mutex); + } +} + /* Prepare for a mode set. * * Note we could be a lot smarter here. We need to figure out which outputs @@ -5163,6 +5177,7 @@ static struct drm_crtc_helper_funcs intel_helper_funcs = { .mode_set_base = intel_pipe_set_base, .mode_set_base_atomic = intel_pipe_set_base_atomic, .load_lut = intel_crtc_load_lut, + .disable = intel_crtc_disable, }; static const struct drm_crtc_funcs intel_crtc_funcs = { -- cgit v1.1 From a6b17b4367ed5d9bac94bc87d1489de3847fce98 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Tue, 21 Sep 2010 12:34:25 +0100 Subject: drm/i915: Use the correct DPB GMBUS port for GPIOE Signed-off-by: Chris Wilson --- drivers/gpu/drm/i915/intel_dvo.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_dvo.c b/drivers/gpu/drm/i915/intel_dvo.c index ad28bc4..561fbc3 100644 --- a/drivers/gpu/drm/i915/intel_dvo.c +++ b/drivers/gpu/drm/i915/intel_dvo.c @@ -72,7 +72,7 @@ static const struct intel_dvo_device intel_dvo_devices[] = { .name = "ch7017", .dvo_reg = DVOC, .slave_addr = 0x75, - .gpio = GMBUS_PORT_DPD, + .gpio = GMBUS_PORT_DPB, .dev_ops = &ch7017_ops, } }; @@ -386,7 +386,7 @@ void intel_dvo_init(struct drm_device *dev) else if (dvo->type == INTEL_DVO_CHIP_LVDS) gpio = GMBUS_PORT_PANEL; else - gpio = GMBUS_PORT_DPD; + gpio = GMBUS_PORT_DPB; /* Set up the I2C bus necessary for the chip we're probing. * It appears that everything is on GPIOE except for panels -- cgit v1.1 From 4fd21dc8ee6fde52a99042186ff94de1b5e8b43c Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Tue, 21 Sep 2010 14:06:12 +0100 Subject: drm/i915/lvds: Unlock the PP register when panel-fitting As we do not wait for the panel to turn off when we need to adjust the panel-fitting registers we also need to unlock the PLLs as with the non-pfit update path. Signed-off-by: Chris Wilson --- drivers/gpu/drm/i915/intel_lvds.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_lvds.c b/drivers/gpu/drm/i915/intel_lvds.c index 02c5aed..2bcea800 100644 --- a/drivers/gpu/drm/i915/intel_lvds.c +++ b/drivers/gpu/drm/i915/intel_lvds.c @@ -97,6 +97,7 @@ static void intel_lvds_set_power(struct intel_lvds *intel_lvds, bool on) DRM_ERROR("timed out waiting for panel to power off\n"); I915_WRITE(PFIT_CONTROL, 0); intel_lvds->pfit_control = 0; + intel_lvds->pfit_dirty = false; } I915_WRITE(lvds_reg, I915_READ(lvds_reg) & ~LVDS_PORT_EN); @@ -377,8 +378,8 @@ static void intel_lvds_prepare(struct drm_encoder *encoder) I915_READ(PCH_PP_CONTROL) | PANEL_UNLOCK_REGS); } else if (intel_lvds->pfit_dirty) { I915_WRITE(PP_CONTROL, - I915_READ(PP_CONTROL) & ~POWER_TARGET_ON); - I915_WRITE(LVDS, I915_READ(LVDS) & ~LVDS_PORT_EN); + (I915_READ(PP_CONTROL) | PANEL_UNLOCK_REGS) + & ~POWER_TARGET_ON); } else { I915_WRITE(PP_CONTROL, I915_READ(PP_CONTROL) | PANEL_UNLOCK_REGS); @@ -438,6 +439,9 @@ static void intel_lvds_mode_set(struct drm_encoder *encoder, * screen. Should be enabled before the pipe is enabled, according to * register description and PRM. */ + DRM_DEBUG_KMS("applying panel-fitter: %x, %x\n", + intel_lvds->pfit_control, + intel_lvds->pfit_pgm_ratios); if (wait_for((I915_READ(PP_STATUS) & PP_ON) == 0, 1000)) DRM_ERROR("timed out waiting for panel to power off\n"); -- cgit v1.1 From 9e0ae53404700f1e4ae1f33b0ff92948ae0e509d Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Tue, 21 Sep 2010 15:05:24 +0100 Subject: drm/i915: Don't overwrite the returned error-code During i915_gem_create_mmap_offset() if the subsystem reports an error code, use it. Signed-off-by: Chris Wilson --- drivers/gpu/drm/i915/i915_gem.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index 151fa43..734cc08 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -1246,7 +1246,7 @@ i915_gem_create_mmap_offset(struct drm_gem_object *obj) obj->size / PAGE_SIZE, 0, 0); if (!list->file_offset_node) { DRM_ERROR("failed to allocate offset for bo %d\n", obj->name); - ret = -ENOMEM; + ret = -ENOSPC; goto out_free_list; } @@ -1258,9 +1258,9 @@ i915_gem_create_mmap_offset(struct drm_gem_object *obj) } list->hash.key = list->file_offset_node->start; - if (drm_ht_insert_item(&mm->offset_hash, &list->hash)) { + ret = drm_ht_insert_item(&mm->offset_hash, &list->hash); + if (ret) { DRM_ERROR("failed to add to map hash\n"); - ret = -ENOMEM; goto out_free_mm; } -- cgit v1.1 From dfaae392f4461785eb1c92aeaf2a1040b184edba Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Wed, 22 Sep 2010 10:31:52 +0100 Subject: drm/i915: Clear the gpu_write_list on resetting write_domain upon hang Otherwise we will hit a list handling assertion when moving the object to the inactive list. Signed-off-by: Chris Wilson --- drivers/gpu/drm/i915/i915_drv.c | 16 +------------ drivers/gpu/drm/i915/i915_drv.h | 3 +-- drivers/gpu/drm/i915/i915_gem.c | 51 ++++++++++++++++++++++++++++++++--------- 3 files changed, 42 insertions(+), 28 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_drv.c b/drivers/gpu/drm/i915/i915_drv.c index 4e83bb3..2184d29 100644 --- a/drivers/gpu/drm/i915/i915_drv.c +++ b/drivers/gpu/drm/i915/i915_drv.c @@ -395,21 +395,7 @@ int i915_reset(struct drm_device *dev, u8 flags) mutex_lock(&dev->struct_mutex); - /* - * Clear request list - */ - i915_gem_retire_requests(dev); - - /* Remove anything from the flushing lists. The GPU cache is likely - * to be lost on reset along with the data, so simply move the - * lost bo to the inactive list. - */ - i915_gem_reset_flushing_list(dev); - - /* Move everything out of the GPU domains to ensure we do any - * necessary invalidation upon reuse. - */ - i915_gem_reset_inactive_gpu_domains(dev); + i915_gem_reset_lists(dev); /* * Set the domains we want to reset (GRDOM/bits 2 and 3) as diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 12e9f85..5fec2ca 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -1005,8 +1005,7 @@ int i915_gem_object_get_fence_reg(struct drm_gem_object *obj, int i915_gem_object_put_fence_reg(struct drm_gem_object *obj, bool interruptible); void i915_gem_retire_requests(struct drm_device *dev); -void i915_gem_reset_flushing_list(struct drm_device *dev); -void i915_gem_reset_inactive_gpu_domains(struct drm_device *dev); +void i915_gem_reset_lists(struct drm_device *dev); void i915_gem_clflush_object(struct drm_gem_object *obj); void i915_gem_flush_ring(struct drm_device *dev, struct drm_file *file_priv, diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index 734cc08..0ce28c7 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -1682,27 +1682,60 @@ i915_get_gem_seqno(struct drm_device *dev, return ring->get_gem_seqno(dev, ring); } -void i915_gem_reset_flushing_list(struct drm_device *dev) +static void i915_gem_reset_ring_lists(struct drm_i915_private *dev_priv, + struct intel_ring_buffer *ring) { - struct drm_i915_private *dev_priv = dev->dev_private; + while (!list_empty(&ring->request_list)) { + struct drm_i915_gem_request *request; - while (!list_empty(&dev_priv->mm.flushing_list)) { + request = list_first_entry(&ring->request_list, + struct drm_i915_gem_request, + list); + + list_del(&request->list); + list_del(&request->client_list); + kfree(request); + } + + while (!list_empty(&ring->active_list)) { struct drm_i915_gem_object *obj_priv; - obj_priv = list_first_entry(&dev_priv->mm.flushing_list, + obj_priv = list_first_entry(&ring->active_list, struct drm_i915_gem_object, list); obj_priv->base.write_domain = 0; + list_del_init(&obj_priv->gpu_write_list); i915_gem_object_move_to_inactive(&obj_priv->base); } } -void i915_gem_reset_inactive_gpu_domains(struct drm_device *dev) +void i915_gem_reset_lists(struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; struct drm_i915_gem_object *obj_priv; + i915_gem_reset_ring_lists(dev_priv, &dev_priv->render_ring); + if (HAS_BSD(dev)) + i915_gem_reset_ring_lists(dev_priv, &dev_priv->bsd_ring); + + /* Remove anything from the flushing lists. The GPU cache is likely + * to be lost on reset along with the data, so simply move the + * lost bo to the inactive list. + */ + while (!list_empty(&dev_priv->mm.flushing_list)) { + obj_priv = list_first_entry(&dev_priv->mm.flushing_list, + struct drm_i915_gem_object, + list); + + obj_priv->base.write_domain = 0; + list_del_init(&obj_priv->gpu_write_list); + i915_gem_object_move_to_inactive(&obj_priv->base); + } + + /* Move everything out of the GPU domains to ensure we do any + * necessary invalidation upon reuse. + */ list_for_each_entry(obj_priv, &dev_priv->mm.inactive_list, list) @@ -1720,15 +1753,12 @@ i915_gem_retire_requests_ring(struct drm_device *dev, { drm_i915_private_t *dev_priv = dev->dev_private; uint32_t seqno; - bool wedged; if (!ring->status_page.page_addr || list_empty(&ring->request_list)) return; seqno = i915_get_gem_seqno(dev, ring); - wedged = atomic_read(&dev_priv->mm.wedged); - while (!list_empty(&ring->request_list)) { struct drm_i915_gem_request *request; @@ -1736,7 +1766,7 @@ i915_gem_retire_requests_ring(struct drm_device *dev, struct drm_i915_gem_request, list); - if (!wedged && !i915_seqno_passed(seqno, request->seqno)) + if (!i915_seqno_passed(seqno, request->seqno)) break; trace_i915_gem_request_retire(dev, request->seqno); @@ -1757,8 +1787,7 @@ i915_gem_retire_requests_ring(struct drm_device *dev, struct drm_i915_gem_object, list); - if (!wedged && - !i915_seqno_passed(seqno, obj_priv->last_rendering_seqno)) + if (!i915_seqno_passed(seqno, obj_priv->last_rendering_seqno)) break; obj = &obj_priv->base; -- cgit v1.1 From 2896b5397570f6857fd5d0e0533f640b05b1d162 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Wed, 22 Sep 2010 10:54:48 +0100 Subject: drm/i915: Don't offset the pin used for crt_ddc Previously when converting the GMBUS pin to the GPIO reg, we would offset the pin by one and then use the look-up table. Now that we first try to use the GMBUS pin, we no longer need the offset and can use the value from the VBIOS directly. Reported-by: Carlos R. Mafra Signed-off-by: Chris Wilson --- drivers/gpu/drm/i915/intel_bios.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/intel_bios.c b/drivers/gpu/drm/i915/intel_bios.c index d11bbca..123e31d 100644 --- a/drivers/gpu/drm/i915/intel_bios.c +++ b/drivers/gpu/drm/i915/intel_bios.c @@ -299,7 +299,7 @@ parse_general_definitions(struct drm_i915_private *dev_priv, int bus_pin = general->crt_ddc_gmbus_pin; DRM_DEBUG_KMS("crt_ddc_bus_pin: %d\n", bus_pin); if (bus_pin >= 1 && bus_pin <= 6) - dev_priv->crt_ddc_pin = bus_pin - 1; + dev_priv->crt_ddc_pin = bus_pin; } else { DRM_DEBUG_KMS("BDB_GD too small (%d). Invalid.\n", block_size); -- cgit v1.1 From 5c12a07e8073295ce8b57a822f811ac34e4f8420 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Wed, 22 Sep 2010 11:22:30 +0100 Subject: drm/i915: Drop ring->lazy_request We are not currently using it as intended, so remove the complication. Signed-off-by: Chris Wilson --- drivers/gpu/drm/i915/i915_gem.c | 37 ++++++--------------------------- drivers/gpu/drm/i915/intel_ringbuffer.h | 5 ----- 2 files changed, 6 insertions(+), 36 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index 0ce28c7..3fd69ad 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -1470,24 +1470,12 @@ i915_gem_object_put_pages(struct drm_gem_object *obj) obj_priv->pages = NULL; } -static uint32_t -i915_gem_next_request_seqno(struct drm_device *dev, - struct intel_ring_buffer *ring) -{ - drm_i915_private_t *dev_priv = dev->dev_private; - - ring->outstanding_lazy_request = true; - - return dev_priv->next_seqno; -} - static void i915_gem_object_move_to_active(struct drm_gem_object *obj, struct intel_ring_buffer *ring) { - struct drm_device *dev = obj->dev; + struct drm_i915_private *dev_priv = obj->dev->dev_private; struct drm_i915_gem_object *obj_priv = to_intel_bo(obj); - uint32_t seqno = i915_gem_next_request_seqno(dev, ring); BUG_ON(ring == NULL); obj_priv->ring = ring; @@ -1500,7 +1488,7 @@ i915_gem_object_move_to_active(struct drm_gem_object *obj, /* Move from whatever list we were on to the tail of execution. */ list_move_tail(&obj_priv->list, &ring->active_list); - obj_priv->last_rendering_seqno = seqno; + obj_priv->last_rendering_seqno = dev_priv->next_seqno; } static void @@ -1945,11 +1933,6 @@ i915_gem_flush_ring(struct drm_device *dev, { ring->flush(dev, ring, invalidate_domains, flush_domains); i915_gem_process_flushing_list(dev, flush_domains, ring); - - if (ring->outstanding_lazy_request) { - (void)i915_add_request(dev, file_priv, NULL, ring); - ring->outstanding_lazy_request = false; - } } static void @@ -2098,7 +2081,7 @@ i915_gpu_idle(struct drm_device *dev) return 0; /* Flush everything onto the inactive list. */ - seqno = i915_gem_next_request_seqno(dev, &dev_priv->render_ring); + seqno = dev_priv->next_seqno; i915_gem_flush_ring(dev, NULL, &dev_priv->render_ring, I915_GEM_GPU_DOMAINS, I915_GEM_GPU_DOMAINS); ret = i915_wait_request(dev, seqno, &dev_priv->render_ring); @@ -2106,7 +2089,7 @@ i915_gpu_idle(struct drm_device *dev) return ret; if (HAS_BSD(dev)) { - seqno = i915_gem_next_request_seqno(dev, &dev_priv->render_ring); + seqno = dev_priv->next_seqno; i915_gem_flush_ring(dev, NULL, &dev_priv->bsd_ring, I915_GEM_GPU_DOMAINS, I915_GEM_GPU_DOMAINS); ret = i915_wait_request(dev, seqno, &dev_priv->bsd_ring); @@ -3573,7 +3556,7 @@ i915_gem_do_execbuffer(struct drm_device *dev, void *data, struct drm_i915_gem_request *request = NULL; int ret = 0, ret2, i, pinned = 0; uint64_t exec_offset; - uint32_t seqno, reloc_index; + uint32_t reloc_index; int pin_tries, flips; struct intel_ring_buffer *ring = NULL; @@ -3854,15 +3837,7 @@ i915_gem_do_execbuffer(struct drm_device *dev, void *data, DRM_INFO("%s: move to exec list %p\n", __func__, obj); #endif } - - /* - * Get a seqno representing the execution of the current buffer, - * which we can wait on. We would like to mitigate these interrupts, - * likely by only creating seqnos occasionally (so that we have - * *some* interrupts representing completion of buffers that we can - * wait on when trying to clear up gtt space). - */ - seqno = i915_add_request(dev, file_priv, request, ring); + i915_add_request(dev, file_priv, request, ring); request = NULL; #if WATCH_LRU diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.h b/drivers/gpu/drm/i915/intel_ringbuffer.h index 2d3165f..bfbc488 100644 --- a/drivers/gpu/drm/i915/intel_ringbuffer.h +++ b/drivers/gpu/drm/i915/intel_ringbuffer.h @@ -86,11 +86,6 @@ struct intel_ring_buffer { */ struct list_head request_list; - /** - * Do we have some not yet emitted requests outstanding? - */ - bool outstanding_lazy_request; - wait_queue_head_t irq_queue; drm_local_map_t map; }; -- cgit v1.1 From a5cad620b36f15ef3aad434712ae290640aae96c Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Wed, 22 Sep 2010 13:15:10 +0100 Subject: drm/i915: Disable "disabled FBC" message when a no-op Signed-off-by: Chris Wilson --- drivers/gpu/drm/i915/intel_display.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index e6f7ebf..b923854 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -1110,6 +1110,9 @@ void i8xx_disable_fbc(struct drm_device *dev) /* Disable compression */ fbc_ctl = I915_READ(FBC_CONTROL); + if ((fbc_ctl & FBC_CTL_EN) == 0) + return; + fbc_ctl &= ~FBC_CTL_EN; I915_WRITE(FBC_CONTROL, fbc_ctl); -- cgit v1.1 From 6ec3d0c0e9c0c605696e91048eebaca7b0c36695 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Wed, 22 Sep 2010 18:17:01 +0100 Subject: drm/i915/crt: Use a DDC probe on 0xA0 before load-detect The BIOS writer's guide suggests that a VGA connection will ACK a write to address 0xA0 and that this should be used before doing legacy load-detection. Considering the extreme cost of load-detection, performing an extra DDC seems a risk worth taking. Signed-off-by: Chris Wilson --- drivers/gpu/drm/i915/intel_crt.c | 39 +++++++++++++++++++++++++++++++++++---- 1 file changed, 35 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_crt.c b/drivers/gpu/drm/i915/intel_crt.c index 8e484c9..389fcd2 100644 --- a/drivers/gpu/drm/i915/intel_crt.c +++ b/drivers/gpu/drm/i915/intel_crt.c @@ -261,6 +261,21 @@ static bool intel_crt_detect_hotplug(struct drm_connector *connector) return ret; } +static bool intel_crt_ddc_probe(struct drm_i915_private *dev_priv, int ddc_bus) +{ + u8 buf; + struct i2c_msg msgs[] = { + { + .addr = 0xA0, + .flags = 0, + .len = 1, + .buf = &buf, + }, + }; + /* DDC monitor detect: Does it ACK a write to 0xA0? */ + return i2c_transfer(&dev_priv->gmbus[ddc_bus].adapter, msgs, 1) == 1; +} + static bool intel_crt_detect_ddc(struct drm_encoder *encoder) { struct intel_encoder *intel_encoder = to_intel_encoder(encoder); @@ -270,7 +285,17 @@ static bool intel_crt_detect_ddc(struct drm_encoder *encoder) if (intel_encoder->type != INTEL_OUTPUT_ANALOG) return false; - return intel_ddc_probe(intel_encoder, dev_priv->crt_ddc_pin); + if (intel_crt_ddc_probe(dev_priv, dev_priv->crt_ddc_pin)) { + DRM_DEBUG_KMS("CRT detected via DDC:0xa0\n"); + return true; + } + + if (intel_ddc_probe(intel_encoder, dev_priv->crt_ddc_pin)) { + DRM_DEBUG_KMS("CRT detected via DDC:0x50 [EDID]\n"); + return true; + } + + return false; } static enum drm_connector_status @@ -296,6 +321,8 @@ intel_crt_load_detect(struct drm_crtc *crtc, struct intel_encoder *intel_encoder uint8_t st00; enum drm_connector_status status; + DRM_DEBUG_KMS("starting load-detect on CRT\n"); + if (pipe == 0) { bclrpat_reg = BCLRPAT_A; vtotal_reg = VTOTAL_A; @@ -412,9 +439,10 @@ intel_crt_detect(struct drm_connector *connector, bool force) enum drm_connector_status status; if (I915_HAS_HOTPLUG(dev)) { - if (intel_crt_detect_hotplug(connector)) + if (intel_crt_detect_hotplug(connector)) { + DRM_DEBUG_KMS("CRT detected via hotplug\n"); return connector_status_connected; - else + } else return connector_status_disconnected; } @@ -431,7 +459,10 @@ intel_crt_detect(struct drm_connector *connector, bool force) crtc = intel_get_load_detect_pipe(encoder, connector, NULL, &dpms_mode); if (crtc) { - status = intel_crt_load_detect(crtc, encoder); + if (intel_crt_detect_ddc(&encoder->base)) + status = connector_status_connected; + else + status = intel_crt_load_detect(crtc, encoder); intel_release_load_detect_pipe(encoder, connector, dpms_mode); } else -- cgit v1.1 From 9b74f7348f214b1f99819f0d0da4a1cbabb1e740 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Wed, 22 Sep 2010 19:10:44 +0100 Subject: drm/i915: Fix 945GM regression in e259befd A minor typo caused a single fence register to be incorrectly programmed, resulting in occassional tiling corruption. Reported-and-tested-by: Hans de Bruin Bugzilla: https://bugzilla.kernel.org/show_bug.cgi?id=18962 Signed-off-by: Chris Wilson Cc: stable@kernel.org --- drivers/gpu/drm/i915/i915_gem.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index cf4ffbe..bced9b2 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -2400,7 +2400,7 @@ i915_gem_clear_fence_reg(struct drm_gem_object *obj) I915_WRITE64(FENCE_REG_965_0 + (obj_priv->fence_reg * 8), 0); break; case 3: - if (obj_priv->fence_reg > 8) + if (obj_priv->fence_reg >= 8) fence_reg = FENCE_REG_945_8 + (obj_priv->fence_reg - 8) * 4; else case 2: -- cgit v1.1 From 20f0cd55f68e0678909214c60b3595a22124bdb0 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Thu, 23 Sep 2010 11:00:38 +0100 Subject: drm/i915: Remove the broken flush_ring from page-flip This is already performed with the pipelined flush, so by the time we schedule the flush in the page-flip, the ring is NULL and we OOPs instead. Reported-by: Daniel Vetter Signed-off-by: Chris Wilson --- drivers/gpu/drm/i915/i915_drv.h | 5 ----- drivers/gpu/drm/i915/i915_gem.c | 2 +- drivers/gpu/drm/i915/intel_display.c | 7 +------ 3 files changed, 2 insertions(+), 12 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 5fec2ca..ac41ca1 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -1007,11 +1007,6 @@ int i915_gem_object_put_fence_reg(struct drm_gem_object *obj, void i915_gem_retire_requests(struct drm_device *dev); void i915_gem_reset_lists(struct drm_device *dev); void i915_gem_clflush_object(struct drm_gem_object *obj); -void i915_gem_flush_ring(struct drm_device *dev, - struct drm_file *file_priv, - struct intel_ring_buffer *ring, - uint32_t invalidate_domains, - uint32_t flush_domains); int i915_gem_object_set_domain(struct drm_gem_object *obj, uint32_t read_domains, uint32_t write_domain); diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index 3fd69ad..174e38a 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -1924,7 +1924,7 @@ i915_wait_request(struct drm_device *dev, uint32_t seqno, return i915_do_wait_request(dev, seqno, 1, ring); } -void +static void i915_gem_flush_ring(struct drm_device *dev, struct drm_file *file_priv, struct intel_ring_buffer *ring, diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index b923854..16541ee 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -5028,7 +5028,7 @@ static int intel_crtc_page_flip(struct drm_crtc *crtc, struct intel_unpin_work *work; unsigned long flags, offset; int pipe = intel_crtc->pipe; - u32 was_dirty, pf, pipesrc; + u32 pf, pipesrc; int ret; work = kzalloc(sizeof *work, GFP_KERNEL); @@ -5057,7 +5057,6 @@ static int intel_crtc_page_flip(struct drm_crtc *crtc, obj = intel_fb->obj; mutex_lock(&dev->struct_mutex); - was_dirty = obj->write_domain & I915_GEM_GPU_DOMAINS; ret = intel_pin_and_fence_fb_obj(dev, obj, true); if (ret) goto cleanup_work; @@ -5076,10 +5075,6 @@ static int intel_crtc_page_flip(struct drm_crtc *crtc, atomic_inc(&obj_priv->pending_flip); work->pending_flip_obj = obj; - /* Schedule the pipelined flush */ - if (was_dirty) - i915_gem_flush_ring(dev, NULL, obj_priv->ring, 0, was_dirty); - if (IS_GEN3(dev) || IS_GEN2(dev)) { u32 flip_mask; -- cgit v1.1 From 29e1316ab129f2d3a9ea874e7c9a4cb936f43542 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Wed, 22 Sep 2010 19:10:09 +0100 Subject: drm/i915/tv: Sleep before checking for state changes. We need to wait for the PLLs to settle prior to detecting the state changes. The BIOS writers guide suggests waiting for the next vblank. Reported-by: Carlos R. Mafra Signed-off-by: Chris Wilson --- drivers/gpu/drm/i915/intel_tv.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_tv.c b/drivers/gpu/drm/i915/intel_tv.c index 49ab11c..106560b 100644 --- a/drivers/gpu/drm/i915/intel_tv.c +++ b/drivers/gpu/drm/i915/intel_tv.c @@ -1271,8 +1271,12 @@ intel_tv_detect_type (struct intel_tv *intel_tv) I915_WRITE(TV_DAC, tv_dac); POSTING_READ(TV_DAC); + intel_wait_for_vblank(intel_tv->base.base.dev, + to_intel_crtc(intel_tv->base.base.crtc)->pipe); + type = -1; if (wait_for((tv_dac = I915_READ(TV_DAC)) & TVDAC_STATE_CHG, 20) == 0) { + DRM_DEBUG_KMS("TV detected: %x, %x\n", tv_ctl, tv_dac); /* * A B C * 0 1 1 Composite @@ -1289,8 +1293,7 @@ intel_tv_detect_type (struct intel_tv *intel_tv) DRM_DEBUG_KMS("Detected Component TV connection\n"); type = DRM_MODE_CONNECTOR_Component; } else { - DRM_DEBUG_KMS("Unrecognised TV connection: %x\n", - tv_dac); + DRM_DEBUG_KMS("Unrecognised TV connection\n"); } } -- cgit v1.1 From 123d5c0197d8333c3f5cb9572a0c8299dc611233 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Thu, 23 Sep 2010 16:15:21 +0100 Subject: drm/i915/sdvo: Cleanup connector on error path We weren't unlinking the freed connector from the drm lists, and so hit some use-after-free if we failed to initialise the connector. Reported-and-tested-by: Woody Suwalski Bugzilla: https://bugzilla.kernel.org/show_bug.cgi?id=18342 Signed-off-by: Chris Wilson --- drivers/gpu/drm/i915/intel_sdvo.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_sdvo.c b/drivers/gpu/drm/i915/intel_sdvo.c index e8e902d..60fcef7 100644 --- a/drivers/gpu/drm/i915/intel_sdvo.c +++ b/drivers/gpu/drm/i915/intel_sdvo.c @@ -2170,8 +2170,7 @@ intel_sdvo_tv_init(struct intel_sdvo *intel_sdvo, int type) return true; err: - intel_sdvo_destroy_enhance_property(connector); - kfree(intel_sdvo_connector); + intel_sdvo_destroy(connector); return false; } @@ -2243,8 +2242,7 @@ intel_sdvo_lvds_init(struct intel_sdvo *intel_sdvo, int device) return true; err: - intel_sdvo_destroy_enhance_property(connector); - kfree(intel_sdvo_connector); + intel_sdvo_destroy(connector); return false; } -- cgit v1.1 From cf9a2f3afc75d41a61cbc91e725b9ce0746c400a Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Thu, 23 Sep 2010 16:17:33 +0100 Subject: drm/i915/sdvo: Handle unsupported GET_SUPPORTED_ENHANCEMENTS gracefully In the event that the external chipset doesn't implement the GET_SUPPORTED_ENHANCEMENTS commands, gracefully treat it as having no enhancments rather than bailing. Reported-and-tested-by: Woody Suwalski Bugzilla: https://bugzilla.kernel.org/show_bug.cgi?id=18342 Signed-off-by: Chris Wilson --- drivers/gpu/drm/i915/intel_sdvo.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_sdvo.c b/drivers/gpu/drm/i915/intel_sdvo.c index 60fcef7..ee73e42 100644 --- a/drivers/gpu/drm/i915/intel_sdvo.c +++ b/drivers/gpu/drm/i915/intel_sdvo.c @@ -2520,11 +2520,10 @@ static bool intel_sdvo_create_enhance_property(struct intel_sdvo *intel_sdvo, uint16_t response; } enhancements; - if (!intel_sdvo_get_value(intel_sdvo, - SDVO_CMD_GET_SUPPORTED_ENHANCEMENTS, - &enhancements, sizeof(enhancements))) - return false; - + enhancements.response = 0; + intel_sdvo_get_value(intel_sdvo, + SDVO_CMD_GET_SUPPORTED_ENHANCEMENTS, + &enhancements, sizeof(enhancements)); if (enhancements.response == 0) { DRM_DEBUG_KMS("No enhancement is supported\n"); return true; -- cgit v1.1 From 428d2e828c0a68206e5158a42451487601dc9194 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Thu, 23 Sep 2010 11:16:49 +0100 Subject: drm/i915/lvds: Probe DDC on creation Try to validate the panel's connection by writing to address 0xA0. Bugzilla: https://bugzilla.kernel.org/show_bug.cgi?id=18072 Signed-off-by: Chris Wilson --- drivers/gpu/drm/i915/intel_lvds.c | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/drivers/gpu/drm/i915/intel_lvds.c b/drivers/gpu/drm/i915/intel_lvds.c index 2bcea800..e1f6e05 100644 --- a/drivers/gpu/drm/i915/intel_lvds.c +++ b/drivers/gpu/drm/i915/intel_lvds.c @@ -810,6 +810,22 @@ static bool lvds_is_present_in_vbt(struct drm_device *dev) return false; } +static bool intel_lvds_ddc_probe(struct drm_device *dev) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + u8 buf = 0; + struct i2c_msg msgs[] = { + { + .addr = 0xA0, + .flags = 0, + .len = 1, + .buf = &buf, + }, + }; + struct i2c_adapter *i2c = &dev_priv->gmbus[GMBUS_PORT_PANEL].adapter; + return i2c_transfer(i2c, msgs, 1) == 1; +} + /** * intel_lvds_init - setup LVDS connectors on this device * @dev: drm device @@ -849,6 +865,11 @@ void intel_lvds_init(struct drm_device *dev) gpio = PCH_GPIOC; } + if (!intel_lvds_ddc_probe(dev)) { + DRM_DEBUG_KMS("LVDS did not respond to DDC probe\n"); + return; + } + intel_lvds = kzalloc(sizeof(struct intel_lvds), GFP_KERNEL); if (!intel_lvds) { return; -- cgit v1.1 From 3eee1794ac14f160338622ea57dcace7382ceb8f Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Thu, 23 Sep 2010 16:45:52 +0100 Subject: drm/i915: Remove idle timer debugging messages These have served their purpose and are now just noise in the debug stream. Signed-off-by: Chris Wilson --- drivers/gpu/drm/i915/intel_display.c | 4 ---- 1 file changed, 4 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 16541ee..dda0f64 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -4693,8 +4693,6 @@ static void intel_gpu_idle_timer(unsigned long arg) struct drm_device *dev = (struct drm_device *)arg; drm_i915_private_t *dev_priv = dev->dev_private; - DRM_DEBUG_DRIVER("idle timer fired, downclocking\n"); - dev_priv->busy = false; queue_work(dev_priv->wq, &dev_priv->idle_work); @@ -4708,8 +4706,6 @@ static void intel_crtc_idle_timer(unsigned long arg) struct drm_crtc *crtc = &intel_crtc->base; drm_i915_private_t *dev_priv = crtc->dev->dev_private; - DRM_DEBUG_DRIVER("idle timer fired, downclocking\n"); - intel_crtc->busy = false; queue_work(dev_priv->wq, &dev_priv->idle_work); -- cgit v1.1 From 780f0ca3e0cd3f0677d9149b7e14bf0878d1dbdc Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Thu, 23 Sep 2010 17:45:39 +0100 Subject: drm/i915/ringbuffer: Fix sign of ring space. As we presume space is signed when computing and looking for wrap along, make it so. Reported-by: Owain G. Ainsworth Signed-off-by: Chris Wilson --- drivers/gpu/drm/i915/intel_ringbuffer.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.h b/drivers/gpu/drm/i915/intel_ringbuffer.h index bfbc488..ce52101 100644 --- a/drivers/gpu/drm/i915/intel_ringbuffer.h +++ b/drivers/gpu/drm/i915/intel_ringbuffer.h @@ -31,7 +31,7 @@ struct intel_ring_buffer { unsigned int head; unsigned int tail; - unsigned int space; + int space; struct intel_hw_status_page status_page; u32 irq_gem_seqno; /* last seq seem at irq time */ -- cgit v1.1 From d3849eded23e6c78b19acc1a3a7811a01d2f541d Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Thu, 23 Sep 2010 22:12:23 +0100 Subject: drm/i915: Remove unused dev_priv->panel_wants_dither This is now private to the DVO connector, remove it from the main device private. Signed-off-by: Chris Wilson --- drivers/gpu/drm/i915/i915_drv.h | 1 - drivers/gpu/drm/i915/intel_lvds.c | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index ac41ca1..a5aa11f 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -328,7 +328,6 @@ typedef struct drm_i915_private { /* LVDS info */ int backlight_level; /* restore backlight to this value */ - bool panel_wants_dither; struct drm_display_mode *panel_fixed_mode; struct drm_display_mode *lfp_lvds_vbt_mode; /* if any */ struct drm_display_mode *sdvo_lvds_vbt_mode; /* if any */ diff --git a/drivers/gpu/drm/i915/intel_lvds.c b/drivers/gpu/drm/i915/intel_lvds.c index e1f6e05..1317731 100644 --- a/drivers/gpu/drm/i915/intel_lvds.c +++ b/drivers/gpu/drm/i915/intel_lvds.c @@ -229,7 +229,7 @@ static bool intel_lvds_mode_fixup(struct drm_encoder *encoder, /* Make sure pre-965s set dither correctly */ if (INTEL_INFO(dev)->gen < 4) { - if (dev_priv->panel_wants_dither || dev_priv->lvds_dither) + if (dev_priv->lvds_dither) pfit_control |= PANEL_8TO6_DITHER_ENABLE; } -- cgit v1.1 From e6c3a2a6d358a726c2c52cb0132c9ad8f6f37486 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Thu, 23 Sep 2010 23:04:43 +0100 Subject: drm/i915: Use an uninterruptible wait for page-flips during modeset We need to drain the pending flips prior to disabling the pipe during modeset, and these need to be done in an uninterruptible fashion. Signed-off-by: Chris Wilson --- drivers/gpu/drm/i915/i915_drv.h | 3 --- drivers/gpu/drm/i915/i915_gem.c | 2 +- drivers/gpu/drm/i915/intel_display.c | 29 ++++++++++++++++++++--------- 3 files changed, 21 insertions(+), 13 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index a5aa11f..6aa3431 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -1023,9 +1023,6 @@ int i915_do_wait_request(struct drm_device *dev, uint32_t seqno, bool interruptible, struct intel_ring_buffer *ring); -int i915_gem_wait_for_pending_flip(struct drm_device *dev, - struct drm_gem_object **object_list, - int count); int i915_gem_fault(struct vm_area_struct *vma, struct vm_fault *vmf); int i915_gem_object_set_to_gtt_domain(struct drm_gem_object *obj, int write); diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index 174e38a..dec7bbc 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -3506,7 +3506,7 @@ i915_gem_check_execbuffer (struct drm_i915_gem_execbuffer2 *exec, return 0; } -int +static int i915_gem_wait_for_pending_flip(struct drm_device *dev, struct drm_gem_object **object_list, int count) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index dda0f64..6fbaa63 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -1593,17 +1593,12 @@ intel_pipe_set_base(struct drm_crtc *crtc, int x, int y, } if (old_fb) { + struct drm_i915_private *dev_priv = dev->dev_private; struct drm_gem_object *obj = to_intel_framebuffer(old_fb)->obj; struct drm_i915_gem_object *obj_priv = to_intel_bo(obj); - if (atomic_read(&obj_priv->pending_flip)) { - ret = i915_gem_wait_for_pending_flip(dev, &obj, 1); - if (ret) { - i915_gem_object_unpin(to_intel_framebuffer(crtc->fb)->obj); - mutex_unlock(&dev->struct_mutex); - return ret; - } - } + wait_event(dev_priv->pending_flip_queue, + atomic_read(&obj_priv->pending_flip) == 0); } ret = intel_pipe_set_base_atomic(crtc, crtc->fb, x, y); @@ -1954,6 +1949,20 @@ static void intel_clear_scanline_wait(struct drm_device *dev) } } +static void intel_crtc_wait_for_pending_flips(struct drm_crtc *crtc) +{ + struct drm_i915_gem_object *obj_priv; + struct drm_i915_private *dev_priv; + + if (crtc->fb == NULL) + return; + + obj_priv = to_intel_bo(to_intel_framebuffer(crtc->fb)->obj); + dev_priv = crtc->dev->dev_private; + wait_event(dev_priv->pending_flip_queue, + atomic_read(&obj_priv->pending_flip) == 0); +} + static void ironlake_crtc_enable(struct drm_crtc *crtc) { struct drm_device *dev = crtc->dev; @@ -2130,6 +2139,7 @@ static void ironlake_crtc_disable(struct drm_crtc *crtc) if (!intel_crtc->active) return; + intel_crtc_wait_for_pending_flips(crtc); drm_vblank_off(dev, pipe); intel_crtc_update_cursor(crtc, false); @@ -2377,9 +2387,10 @@ static void i9xx_crtc_disable(struct drm_crtc *crtc) return; /* Give the overlay scaler a chance to disable if it's on this pipe */ + intel_crtc_wait_for_pending_flips(crtc); + drm_vblank_off(dev, pipe); intel_crtc_dpms_overlay(intel_crtc, false); intel_crtc_update_cursor(crtc, false); - drm_vblank_off(dev, pipe); if (dev_priv->cfb_plane == plane && dev_priv->display.disable_fbc) -- cgit v1.1 From 270eea0fd71ae95654606ff7448f195fa22d12c5 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Fri, 24 Sep 2010 01:15:02 +0100 Subject: drm/i915/lvds: Use the GMBUS pin if specified in VBT Signed-off-by: Chris Wilson --- drivers/gpu/drm/i915/intel_lvds.c | 21 +++++++++++++-------- 1 file changed, 13 insertions(+), 8 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_lvds.c b/drivers/gpu/drm/i915/intel_lvds.c index 1317731..95e035a 100644 --- a/drivers/gpu/drm/i915/intel_lvds.c +++ b/drivers/gpu/drm/i915/intel_lvds.c @@ -771,7 +771,8 @@ static void intel_find_lvds_downclock(struct drm_device *dev, * If it is not present, return false. * If no child dev is parsed from VBT, it assumes that the LVDS is present. */ -static bool lvds_is_present_in_vbt(struct drm_device *dev) +static bool lvds_is_present_in_vbt(struct drm_device *dev, + u8 *i2c_pin) { struct drm_i915_private *dev_priv = dev->dev_private; int i; @@ -790,6 +791,9 @@ static bool lvds_is_present_in_vbt(struct drm_device *dev) child->device_type != DEVICE_TYPE_LFP) continue; + if (child->i2c_pin) + *i2c_pin = child->i2c_pin; + /* However, we cannot trust the BIOS writers to populate * the VBT correctly. Since LVDS requires additional * information from AIM blocks, a non-zero addin offset is @@ -810,7 +814,7 @@ static bool lvds_is_present_in_vbt(struct drm_device *dev) return false; } -static bool intel_lvds_ddc_probe(struct drm_device *dev) +static bool intel_lvds_ddc_probe(struct drm_device *dev, u8 pin) { struct drm_i915_private *dev_priv = dev->dev_private; u8 buf = 0; @@ -822,7 +826,7 @@ static bool intel_lvds_ddc_probe(struct drm_device *dev) .buf = &buf, }, }; - struct i2c_adapter *i2c = &dev_priv->gmbus[GMBUS_PORT_PANEL].adapter; + struct i2c_adapter *i2c = &dev_priv->gmbus[pin].adapter; return i2c_transfer(i2c, msgs, 1) == 1; } @@ -844,13 +848,15 @@ void intel_lvds_init(struct drm_device *dev) struct drm_display_mode *scan; /* *modes, *bios_mode; */ struct drm_crtc *crtc; u32 lvds; - int pipe, gpio = GPIOC; + int pipe; + u8 pin; /* Skip init on machines we know falsely report LVDS */ if (dmi_check_system(intel_no_lvds)) return; - if (!lvds_is_present_in_vbt(dev)) { + pin = GMBUS_PORT_PANEL; + if (!lvds_is_present_in_vbt(dev, &pin)) { DRM_DEBUG_KMS("LVDS is not present in VBT\n"); return; } @@ -862,10 +868,9 @@ void intel_lvds_init(struct drm_device *dev) DRM_DEBUG_KMS("disable LVDS for eDP support\n"); return; } - gpio = PCH_GPIOC; } - if (!intel_lvds_ddc_probe(dev)) { + if (!intel_lvds_ddc_probe(dev, pin)) { DRM_DEBUG_KMS("LVDS did not respond to DDC probe\n"); return; } @@ -930,7 +935,7 @@ void intel_lvds_init(struct drm_device *dev) * preferred mode is the right one. */ intel_lvds->edid = drm_get_edid(connector, - &dev_priv->gmbus[GMBUS_PORT_PANEL].adapter); + &dev_priv->gmbus[pin].adapter); if (!intel_lvds->edid) { /* Didn't get an EDID, so -- cgit v1.1 From 5ceb0f9bb7bde101d8b07cb803002591dcb8c804 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Fri, 24 Sep 2010 10:24:28 +0100 Subject: drm/i915: Parse the eDP link configuration from the vBIOS First step, lets have a look at the values for troublesome panels and see if they may be used to improve our link training. Signed-off-by: Chris Wilson --- drivers/gpu/drm/i915/i915_drv.h | 13 ++++++++++-- drivers/gpu/drm/i915/intel_bios.c | 41 ++++++++++++++++++++++++------------ drivers/gpu/drm/i915/intel_display.c | 2 +- drivers/gpu/drm/i915/intel_dp.c | 4 ++-- drivers/gpu/drm/i915/intel_lvds.c | 2 +- 5 files changed, 42 insertions(+), 20 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 6aa3431..cbfb99d 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -338,9 +338,18 @@ typedef struct drm_i915_private { unsigned int lvds_vbt:1; unsigned int int_crt_support:1; unsigned int lvds_use_ssc:1; - unsigned int edp_support:1; int lvds_ssc_freq; - int edp_bpp; + + struct { + u8 rate:4; + u8 lanes:4; + u8 preemphasis:4; + u8 vswing:4; + + u8 initialized:1; + u8 support:1; + u8 bpp:6; + } edp; struct notifier_block lid_notifier; diff --git a/drivers/gpu/drm/i915/intel_bios.c b/drivers/gpu/drm/i915/intel_bios.c index 123e31d..42a7a5b 100644 --- a/drivers/gpu/drm/i915/intel_bios.c +++ b/drivers/gpu/drm/i915/intel_bios.c @@ -401,14 +401,11 @@ parse_driver_features(struct drm_i915_private *dev_priv, if (!driver) return; - if (driver && SUPPORTS_EDP(dev) && - driver->lvds_config == BDB_DRIVER_FEATURE_EDP) { - dev_priv->edp_support = 1; - } else { - dev_priv->edp_support = 0; - } + if (SUPPORTS_EDP(dev) && + driver->lvds_config == BDB_DRIVER_FEATURE_EDP) + dev_priv->edp.support = 1; - if (driver && driver->dual_frequency) + if (driver->dual_frequency) dev_priv->render_reclock_avail = true; } @@ -417,28 +414,44 @@ parse_edp(struct drm_i915_private *dev_priv, struct bdb_header *bdb) { struct bdb_edp *edp; + dev_priv->edp.bpp = 18; + edp = find_section(bdb, BDB_EDP); if (!edp) { - if (SUPPORTS_EDP(dev_priv->dev) && dev_priv->edp_support) { + if (SUPPORTS_EDP(dev_priv->dev) && dev_priv->edp.support) { DRM_DEBUG_KMS("No eDP BDB found but eDP panel " - "supported, assume 18bpp panel color " - "depth.\n"); - dev_priv->edp_bpp = 18; + "supported, assume %dbpp panel color " + "depth.\n", + dev_priv->edp.bpp); } return; } switch ((edp->color_depth >> (panel_type * 2)) & 3) { case EDP_18BPP: - dev_priv->edp_bpp = 18; + dev_priv->edp.bpp = 18; break; case EDP_24BPP: - dev_priv->edp_bpp = 24; + dev_priv->edp.bpp = 24; break; case EDP_30BPP: - dev_priv->edp_bpp = 30; + dev_priv->edp.bpp = 30; break; } + + dev_priv->edp.rate = edp->link_params[panel_type].rate; + dev_priv->edp.lanes = edp->link_params[panel_type].lanes; + dev_priv->edp.preemphasis = edp->link_params[panel_type].preemphasis; + dev_priv->edp.vswing = edp->link_params[panel_type].vswing; + + DRM_DEBUG_KMS("eDP vBIOS settings: bpp=%d, rate=%d, lanes=%d, preemphasis=%d, vswing=%d\n", + dev_priv->edp.bpp, + dev_priv->edp.rate, + dev_priv->edp.lanes, + dev_priv->edp.preemphasis, + dev_priv->edp.vswing); + + dev_priv->edp.initialized = true; } static void diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 6fbaa63..4843d02 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -3705,7 +3705,7 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc, else temp |= PIPE_6BPC; } else if (has_edp_encoder || (is_dp && intel_pch_has_edp(crtc))) { - switch (dev_priv->edp_bpp/3) { + switch (dev_priv->edp.bpp/3) { case 8: temp |= PIPE_8BPC; break; diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c index ec26ee7..117eb99 100644 --- a/drivers/gpu/drm/i915/intel_dp.c +++ b/drivers/gpu/drm/i915/intel_dp.c @@ -139,7 +139,7 @@ intel_dp_link_required(struct drm_device *dev, struct intel_dp *intel_dp, int pi struct drm_i915_private *dev_priv = dev->dev_private; if (IS_eDP(intel_dp) || IS_PCH_eDP(intel_dp)) - return (pixel_clock * dev_priv->edp_bpp) / 8; + return (pixel_clock * dev_priv->edp.bpp + 7) / 8; else return pixel_clock * 3; } @@ -653,7 +653,7 @@ intel_dp_set_m_n(struct drm_crtc *crtc, struct drm_display_mode *mode, if (intel_dp->base.type == INTEL_OUTPUT_DISPLAYPORT) { lane_count = intel_dp->lane_count; if (IS_PCH_eDP(intel_dp)) - bpp = dev_priv->edp_bpp; + bpp = dev_priv->edp.bpp; break; } } diff --git a/drivers/gpu/drm/i915/intel_lvds.c b/drivers/gpu/drm/i915/intel_lvds.c index 95e035a..98172bc 100644 --- a/drivers/gpu/drm/i915/intel_lvds.c +++ b/drivers/gpu/drm/i915/intel_lvds.c @@ -864,7 +864,7 @@ void intel_lvds_init(struct drm_device *dev) if (HAS_PCH_SPLIT(dev)) { if ((I915_READ(PCH_LVDS) & LVDS_DETECTED) == 0) return; - if (dev_priv->edp_support) { + if (dev_priv->edp.support) { DRM_DEBUG_KMS("disable LVDS for eDP support\n"); return; } -- cgit v1.1 From e61cb0d5fd172ab95a4501917526382f25158e83 Mon Sep 17 00:00:00 2001 From: Jan Beulich Date: Fri, 24 Sep 2010 13:25:30 +0100 Subject: some clean up to intel-gtt.c In commit e517a5e97080bbe52857bd0d7df9b66602d53c4d the call to map_page_into_agp() got removed from intel_i830_setup_flush(), but the counterpart call from intel_i830_fini_flush() to unmap_page_from_agp() was left in place. Additionally, the page allocated here never gets its physical address used for sending to hardware, so there's no need to allocate it with GFP_DMA32. Nor is __GFP_ZERO really necessary, as the page is used only to store data to force flushing of some internal processor state. Signed-off-by: Jan Beulich Cc: Eric Anholt Signed-off-by: Chris Wilson --- drivers/char/agp/intel-gtt.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/char/agp/intel-gtt.c b/drivers/char/agp/intel-gtt.c index 9a03815..0c8ff6d 100644 --- a/drivers/char/agp/intel-gtt.c +++ b/drivers/char/agp/intel-gtt.c @@ -814,7 +814,6 @@ static void i830_cleanup(void) { kunmap(intel_private.i8xx_page); intel_private.i8xx_flush_page = NULL; - unmap_page_from_agp(intel_private.i8xx_page); __free_page(intel_private.i8xx_page); intel_private.i8xx_page = NULL; @@ -826,7 +825,7 @@ static void intel_i830_setup_flush(void) if (intel_private.i8xx_page) return; - intel_private.i8xx_page = alloc_page(GFP_KERNEL | __GFP_ZERO | GFP_DMA32); + intel_private.i8xx_page = alloc_page(GFP_KERNEL); if (!intel_private.i8xx_page) return; -- cgit v1.1 From 27d64339a8d8465484286a2da93f5f6c36be5c3d Mon Sep 17 00:00:00 2001 From: Hette Visser Date: Fri, 24 Sep 2010 10:51:30 +0100 Subject: drm/i915/dp: Wait for PP_CONTROL to take effect. This patch fixes the black screen bug on Dell e6510, by adding two delays to give the eDP panel time to turn on before we continue with the next write. 300ms is rather arbitray and a rather long sleep, we need to find a way of refining this value. Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=29278 Signed-off-by: Chris Wilson Acked-by: Jesse Barnes --- 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 117eb99..d19334a 100644 --- a/drivers/gpu/drm/i915/intel_dp.c +++ b/drivers/gpu/drm/i915/intel_dp.c @@ -784,6 +784,11 @@ static bool ironlake_edp_panel_on (struct drm_device *dev) pp |= POWER_TARGET_ON; I915_WRITE(PCH_PP_CONTROL, pp); + /* Ouch. We need to wait here for some panels, like Dell e6510 + * https://bugs.freedesktop.org/show_bug.cgi?id=29278i + */ + msleep(300); + if (wait_for(I915_READ(PCH_PP_STATUS) & PP_ON, 5000)) DRM_ERROR("panel on wait timed out: 0x%08x\n", I915_READ(PCH_PP_STATUS)); @@ -819,6 +824,11 @@ static void ironlake_edp_panel_off (struct drm_device *dev) pp |= PANEL_POWER_RESET; /* restore panel reset bit */ I915_WRITE(PCH_PP_CONTROL, pp); POSTING_READ(PCH_PP_CONTROL); + + /* Ouch. We need to wait here for some panels, like Dell e6510 + * https://bugs.freedesktop.org/show_bug.cgi?id=29278i + */ + msleep(300); } static void ironlake_edp_panel_vdd_on(struct drm_device *dev) -- cgit v1.1 From f787a5f59e1b0e320a6b0a37e9a2e306551d1e40 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Fri, 24 Sep 2010 16:02:42 +0100 Subject: drm/i915: Only hold a process-local lock whilst throttling. Avoid cause latencies in other clients by not taking the global struct mutex and moving the per-client request manipulation a local per-client mutex. For example, this allows a compositor to schedule a page-flip (through X) whilst an OpenGL application is monopolising the GPU. Signed-off-by: Chris Wilson --- drivers/gpu/drm/i915/i915_debugfs.c | 6 +- drivers/gpu/drm/i915/i915_dma.c | 22 +++--- drivers/gpu/drm/i915/i915_drv.h | 15 +++- drivers/gpu/drm/i915/i915_gem.c | 120 +++++++++++++++++++------------- drivers/gpu/drm/i915/i915_irq.c | 29 ++++---- drivers/gpu/drm/i915/intel_display.c | 2 +- drivers/gpu/drm/i915/intel_ringbuffer.c | 16 ++--- drivers/gpu/drm/i915/intel_ringbuffer.h | 5 +- 8 files changed, 123 insertions(+), 92 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_debugfs.c b/drivers/gpu/drm/i915/i915_debugfs.c index 36f0e36..eb5dd52 100644 --- a/drivers/gpu/drm/i915/i915_debugfs.c +++ b/drivers/gpu/drm/i915/i915_debugfs.c @@ -261,7 +261,7 @@ static int i915_gem_seqno_info(struct seq_file *m, void *data) if (dev_priv->render_ring.status_page.page_addr != NULL) { seq_printf(m, "Current sequence: %d\n", - i915_get_gem_seqno(dev, &dev_priv->render_ring)); + dev_priv->render_ring.get_seqno(dev, &dev_priv->render_ring)); } else { seq_printf(m, "Current sequence: hws uninitialized\n"); } @@ -321,7 +321,7 @@ static int i915_interrupt_info(struct seq_file *m, void *data) atomic_read(&dev_priv->irq_received)); if (dev_priv->render_ring.status_page.page_addr != NULL) { seq_printf(m, "Current sequence: %d\n", - i915_get_gem_seqno(dev, &dev_priv->render_ring)); + dev_priv->render_ring.get_seqno(dev, &dev_priv->render_ring)); } else { seq_printf(m, "Current sequence: hws uninitialized\n"); } @@ -932,7 +932,7 @@ i915_wedged_write(struct file *filp, atomic_set(&dev_priv->mm.wedged, val); if (val) { - DRM_WAKEUP(&dev_priv->irq_queue); + wake_up_all(&dev_priv->irq_queue); queue_work(dev_priv->wq, &dev_priv->error_work); } diff --git a/drivers/gpu/drm/i915/i915_dma.c b/drivers/gpu/drm/i915/i915_dma.c index 048c54b..a3aea17 100644 --- a/drivers/gpu/drm/i915/i915_dma.c +++ b/drivers/gpu/drm/i915/i915_dma.c @@ -2162,20 +2162,19 @@ int i915_driver_unload(struct drm_device *dev) return 0; } -int i915_driver_open(struct drm_device *dev, struct drm_file *file_priv) +int i915_driver_open(struct drm_device *dev, struct drm_file *file) { - struct drm_i915_file_private *i915_file_priv; + struct drm_i915_file_private *file_priv; DRM_DEBUG_DRIVER("\n"); - i915_file_priv = (struct drm_i915_file_private *) - kmalloc(sizeof(*i915_file_priv), GFP_KERNEL); - - if (!i915_file_priv) + file_priv = kmalloc(sizeof(*file_priv), GFP_KERNEL); + if (!file_priv) return -ENOMEM; - file_priv->driver_priv = i915_file_priv; + file->driver_priv = file_priv; - INIT_LIST_HEAD(&i915_file_priv->mm.request_list); + INIT_LIST_HEAD(&file_priv->mm.request_list); + mutex_init(&file_priv->mutex); return 0; } @@ -2218,11 +2217,12 @@ void i915_driver_preclose(struct drm_device * dev, struct drm_file *file_priv) i915_mem_release(dev, file_priv, dev_priv->agp_heap); } -void i915_driver_postclose(struct drm_device *dev, struct drm_file *file_priv) +void i915_driver_postclose(struct drm_device *dev, struct drm_file *file) { - struct drm_i915_file_private *i915_file_priv = file_priv->driver_priv; + struct drm_i915_file_private *file_priv = file->driver_priv; - kfree(i915_file_priv); + mutex_destroy(&file_priv->mutex); + kfree(file_priv); } struct drm_ioctl_desc i915_ioctls[] = { diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index cbfb99d..2611e85b 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -844,11 +844,13 @@ struct drm_i915_gem_request { /** global list entry for this request */ struct list_head list; + struct drm_i915_file_private *file_priv; /** file_priv list entry for this request */ struct list_head client_list; }; struct drm_i915_file_private { + struct mutex mutex; struct { struct list_head request_list; } mm; @@ -1005,9 +1007,16 @@ void i915_gem_object_unpin(struct drm_gem_object *obj); int i915_gem_object_unbind(struct drm_gem_object *obj); void i915_gem_release_mmap(struct drm_gem_object *obj); void i915_gem_lastclose(struct drm_device *dev); -uint32_t i915_get_gem_seqno(struct drm_device *dev, - struct intel_ring_buffer *ring); -bool i915_seqno_passed(uint32_t seq1, uint32_t seq2); + +/** + * Returns true if seq1 is later than seq2. + */ +static inline bool +i915_seqno_passed(uint32_t seq1, uint32_t seq2) +{ + return (int32_t)(seq1 - seq2) >= 0; +} + int i915_gem_object_get_fence_reg(struct drm_gem_object *obj, bool interruptible); int i915_gem_object_put_fence_reg(struct drm_gem_object *obj, diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index dec7bbc..9185f09 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -1592,17 +1592,17 @@ i915_gem_process_flushing_list(struct drm_device *dev, uint32_t i915_add_request(struct drm_device *dev, - struct drm_file *file_priv, + struct drm_file *file, struct drm_i915_gem_request *request, struct intel_ring_buffer *ring) { drm_i915_private_t *dev_priv = dev->dev_private; - struct drm_i915_file_private *i915_file_priv = NULL; + struct drm_i915_file_private *file_priv = NULL; uint32_t seqno; int was_empty; - if (file_priv != NULL) - i915_file_priv = file_priv->driver_priv; + if (file != NULL) + file_priv = file->driver_priv; if (request == NULL) { request = kzalloc(sizeof(*request), GFP_KERNEL); @@ -1610,7 +1610,7 @@ i915_add_request(struct drm_device *dev, return 0; } - seqno = ring->add_request(dev, ring, file_priv, 0); + seqno = ring->add_request(dev, ring, 0); request->seqno = seqno; request->ring = ring; @@ -1618,11 +1618,12 @@ i915_add_request(struct drm_device *dev, was_empty = list_empty(&ring->request_list); list_add_tail(&request->list, &ring->request_list); - if (i915_file_priv) { + if (file_priv) { + mutex_lock(&file_priv->mutex); + request->file_priv = file_priv; list_add_tail(&request->client_list, - &i915_file_priv->mm.request_list); - } else { - INIT_LIST_HEAD(&request->client_list); + &file_priv->mm.request_list); + mutex_unlock(&file_priv->mutex); } if (!dev_priv->mm.suspended) { @@ -1654,20 +1655,14 @@ i915_retire_commands(struct drm_device *dev, struct intel_ring_buffer *ring) I915_GEM_DOMAIN_COMMAND, flush_domains); } -/** - * Returns true if seq1 is later than seq2. - */ -bool -i915_seqno_passed(uint32_t seq1, uint32_t seq2) -{ - return (int32_t)(seq1 - seq2) >= 0; -} - -uint32_t -i915_get_gem_seqno(struct drm_device *dev, - struct intel_ring_buffer *ring) +static inline void +i915_gem_request_remove_from_client(struct drm_i915_gem_request *request) { - return ring->get_gem_seqno(dev, ring); + if (request->file_priv) { + mutex_lock(&request->file_priv->mutex); + list_del(&request->client_list); + mutex_unlock(&request->file_priv->mutex); + } } static void i915_gem_reset_ring_lists(struct drm_i915_private *dev_priv, @@ -1681,7 +1676,7 @@ static void i915_gem_reset_ring_lists(struct drm_i915_private *dev_priv, list); list_del(&request->list); - list_del(&request->client_list); + i915_gem_request_remove_from_client(request); kfree(request); } @@ -1746,7 +1741,7 @@ i915_gem_retire_requests_ring(struct drm_device *dev, list_empty(&ring->request_list)) return; - seqno = i915_get_gem_seqno(dev, ring); + seqno = ring->get_seqno(dev, ring); while (!list_empty(&ring->request_list)) { struct drm_i915_gem_request *request; @@ -1760,7 +1755,7 @@ i915_gem_retire_requests_ring(struct drm_device *dev, trace_i915_gem_request_retire(dev, request->seqno); list_del(&request->list); - list_del(&request->client_list); + i915_gem_request_remove_from_client(request); kfree(request); } @@ -1862,7 +1857,7 @@ i915_do_wait_request(struct drm_device *dev, uint32_t seqno, if (atomic_read(&dev_priv->mm.wedged)) return -EIO; - if (!i915_seqno_passed(ring->get_gem_seqno(dev, ring), seqno)) { + if (!i915_seqno_passed(ring->get_seqno(dev, ring), seqno)) { if (HAS_PCH_SPLIT(dev)) ier = I915_READ(DEIER) | I915_READ(GTIER); else @@ -1881,12 +1876,12 @@ i915_do_wait_request(struct drm_device *dev, uint32_t seqno, if (interruptible) ret = wait_event_interruptible(ring->irq_queue, i915_seqno_passed( - ring->get_gem_seqno(dev, ring), seqno) + ring->get_seqno(dev, ring), seqno) || atomic_read(&dev_priv->mm.wedged)); else wait_event(ring->irq_queue, i915_seqno_passed( - ring->get_gem_seqno(dev, ring), seqno) + ring->get_seqno(dev, ring), seqno) || atomic_read(&dev_priv->mm.wedged)); ring->user_irq_put(dev, ring); @@ -1899,7 +1894,7 @@ i915_do_wait_request(struct drm_device *dev, uint32_t seqno, if (ret && ret != -ERESTARTSYS) DRM_ERROR("%s returns %d (awaiting %d at %d, next %d)\n", - __func__, ret, seqno, ring->get_gem_seqno(dev, ring), + __func__, ret, seqno, ring->get_seqno(dev, ring), dev_priv->next_seqno); /* Directly dispatch request retiring. While we have the work queue @@ -3384,28 +3379,48 @@ i915_gem_object_pin_and_relocate(struct drm_gem_object *obj, * relatively low latency when blocking on a particular request to finish. */ static int -i915_gem_ring_throttle(struct drm_device *dev, struct drm_file *file_priv) +i915_gem_ring_throttle(struct drm_device *dev, struct drm_file *file) { - struct drm_i915_file_private *i915_file_priv = file_priv->driver_priv; - int ret = 0; + struct drm_i915_private *dev_priv = dev->dev_private; + struct drm_i915_file_private *file_priv = file->driver_priv; unsigned long recent_enough = jiffies - msecs_to_jiffies(20); + struct drm_i915_gem_request *request; + struct intel_ring_buffer *ring = NULL; + u32 seqno = 0; + int ret; - mutex_lock(&dev->struct_mutex); - while (!list_empty(&i915_file_priv->mm.request_list)) { - struct drm_i915_gem_request *request; - - request = list_first_entry(&i915_file_priv->mm.request_list, - struct drm_i915_gem_request, - client_list); - + mutex_lock(&file_priv->mutex); + list_for_each_entry(request, &file_priv->mm.request_list, client_list) { if (time_after_eq(request->emitted_jiffies, recent_enough)) break; - ret = i915_wait_request(dev, request->seqno, request->ring); - if (ret != 0) - break; + ring = request->ring; + seqno = request->seqno; } - mutex_unlock(&dev->struct_mutex); + mutex_unlock(&file_priv->mutex); + + if (seqno == 0) + return 0; + + ret = 0; + if (!i915_seqno_passed(ring->get_seqno(dev, ring), seqno)) { + /* And wait for the seqno passing without holding any locks and + * causing extra latency for others. This is safe as the irq + * generation is designed to be run atomically and so is + * lockless. + */ + ring->user_irq_get(dev, ring); + ret = wait_event_interruptible(ring->irq_queue, + i915_seqno_passed(ring->get_seqno(dev, ring), seqno) + || atomic_read(&dev_priv->mm.wedged)); + ring->user_irq_put(dev, ring); + + if (ret == 0 && atomic_read(&dev_priv->mm.wedged)) + ret = -EIO; + } + + if (ret == 0) + queue_delayed_work(dev_priv->wq, &dev_priv->mm.retire_work, 0); return ret; } @@ -4857,17 +4872,26 @@ i915_gem_phys_pwrite(struct drm_device *dev, struct drm_gem_object *obj, return 0; } -void i915_gem_release(struct drm_device * dev, struct drm_file *file_priv) +void i915_gem_release(struct drm_device *dev, struct drm_file *file) { - struct drm_i915_file_private *i915_file_priv = file_priv->driver_priv; + struct drm_i915_file_private *file_priv = file->driver_priv; /* Clean up our request list when the client is going away, so that * later retire_requests won't dereference our soon-to-be-gone * file_priv. */ mutex_lock(&dev->struct_mutex); - while (!list_empty(&i915_file_priv->mm.request_list)) - list_del_init(i915_file_priv->mm.request_list.next); + mutex_lock(&file_priv->mutex); + while (!list_empty(&file_priv->mm.request_list)) { + struct drm_i915_gem_request *request; + + request = list_first_entry(&file_priv->mm.request_list, + struct drm_i915_gem_request, + client_list); + list_del(&request->client_list); + request->file_priv = NULL; + } + mutex_unlock(&file_priv->mutex); mutex_unlock(&dev->struct_mutex); } diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c index d4c053e..245a07e 100644 --- a/drivers/gpu/drm/i915/i915_irq.c +++ b/drivers/gpu/drm/i915/i915_irq.c @@ -327,16 +327,16 @@ static irqreturn_t ironlake_irq_handler(struct drm_device *dev) } if (gt_iir & GT_PIPE_NOTIFY) { - u32 seqno = render_ring->get_gem_seqno(dev, render_ring); + u32 seqno = render_ring->get_seqno(dev, render_ring); render_ring->irq_gem_seqno = seqno; trace_i915_gem_request_complete(dev, seqno); - DRM_WAKEUP(&dev_priv->render_ring.irq_queue); + wake_up_all(&dev_priv->render_ring.irq_queue); dev_priv->hangcheck_count = 0; mod_timer(&dev_priv->hangcheck_timer, jiffies + msecs_to_jiffies(DRM_I915_HANGCHECK_PERIOD)); } if (gt_iir & bsd_usr_interrupt) - DRM_WAKEUP(&dev_priv->bsd_ring.irq_queue); + wake_up_all(&dev_priv->bsd_ring.irq_queue); if (de_iir & DE_GSE) intel_opregion_gse_intr(dev); @@ -573,7 +573,8 @@ static void i915_capture_error_state(struct drm_device *dev) return; } - error->seqno = i915_get_gem_seqno(dev, &dev_priv->render_ring); + error->seqno = + dev_priv->render_ring.get_seqno(dev, &dev_priv->render_ring); error->eir = I915_READ(EIR); error->pgtbl_er = I915_READ(PGTBL_ER); error->pipeastat = I915_READ(PIPEASTAT); @@ -873,7 +874,9 @@ static void i915_handle_error(struct drm_device *dev, bool wedged) /* * Wakeup waiting processes so they don't hang */ - DRM_WAKEUP(&dev_priv->render_ring.irq_queue); + wake_up_all(&dev_priv->render_ring.irq_queue); + if (HAS_BSD(dev)) + wake_up_all(&dev_priv->bsd_ring.irq_queue); } queue_work(dev_priv->wq, &dev_priv->error_work); @@ -1012,18 +1015,17 @@ irqreturn_t i915_driver_irq_handler(DRM_IRQ_ARGS) } if (iir & I915_USER_INTERRUPT) { - u32 seqno = - render_ring->get_gem_seqno(dev, render_ring); + u32 seqno = render_ring->get_seqno(dev, render_ring); render_ring->irq_gem_seqno = seqno; trace_i915_gem_request_complete(dev, seqno); - DRM_WAKEUP(&dev_priv->render_ring.irq_queue); + wake_up_all(&dev_priv->render_ring.irq_queue); dev_priv->hangcheck_count = 0; mod_timer(&dev_priv->hangcheck_timer, jiffies + msecs_to_jiffies(DRM_I915_HANGCHECK_PERIOD)); } if (HAS_BSD(dev) && (iir & I915_BSD_USER_INTERRUPT)) - DRM_WAKEUP(&dev_priv->bsd_ring.irq_queue); + wake_up_all(&dev_priv->bsd_ring.irq_queue); if (iir & I915_DISPLAY_PLANE_A_FLIP_PENDING_INTERRUPT) { intel_prepare_page_flip(dev, 0); @@ -1333,9 +1335,8 @@ void i915_hangcheck_elapsed(unsigned long data) /* If all work is done then ACTHD clearly hasn't advanced. */ if (list_empty(&dev_priv->render_ring.request_list) || - i915_seqno_passed(i915_get_gem_seqno(dev, - &dev_priv->render_ring), - i915_get_tail_request(dev)->seqno)) { + i915_seqno_passed(dev_priv->render_ring.get_seqno(dev, &dev_priv->render_ring), + i915_get_tail_request(dev)->seqno)) { bool missed_wakeup = false; dev_priv->hangcheck_count = 0; @@ -1343,13 +1344,13 @@ void i915_hangcheck_elapsed(unsigned long data) /* Issue a wake-up to catch stuck h/w. */ if (dev_priv->render_ring.waiting_gem_seqno && waitqueue_active(&dev_priv->render_ring.irq_queue)) { - DRM_WAKEUP(&dev_priv->render_ring.irq_queue); + wake_up_all(&dev_priv->render_ring.irq_queue); missed_wakeup = true; } if (dev_priv->bsd_ring.waiting_gem_seqno && waitqueue_active(&dev_priv->bsd_ring.irq_queue)) { - DRM_WAKEUP(&dev_priv->bsd_ring.irq_queue); + wake_up_all(&dev_priv->bsd_ring.irq_queue); missed_wakeup = true; } diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 4843d02..00214c1 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -4983,7 +4983,7 @@ static void do_intel_finish_page_flip(struct drm_device *dev, /* Initial scanout buffer will have a 0 pending flip count */ if ((atomic_read(&obj_priv->pending_flip) == 0) || atomic_dec_and_test(&obj_priv->pending_flip)) - DRM_WAKEUP(&dev_priv->pending_flip_queue); + wake_up(&dev_priv->pending_flip_queue); schedule_work(&work->work); trace_i915_flip_complete(intel_crtc->plane, work->pending_flip_obj); diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.c b/drivers/gpu/drm/i915/intel_ringbuffer.c index 1bcea7c..9b848be 100644 --- a/drivers/gpu/drm/i915/intel_ringbuffer.c +++ b/drivers/gpu/drm/i915/intel_ringbuffer.c @@ -239,7 +239,6 @@ do { \ static u32 render_ring_add_request(struct drm_device *dev, struct intel_ring_buffer *ring, - struct drm_file *file_priv, u32 flush_domains) { drm_i915_private_t *dev_priv = dev->dev_private; @@ -303,8 +302,8 @@ render_ring_add_request(struct drm_device *dev, } static u32 -render_ring_get_gem_seqno(struct drm_device *dev, - struct intel_ring_buffer *ring) +render_ring_get_seqno(struct drm_device *dev, + struct intel_ring_buffer *ring) { drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; if (HAS_PIPE_CONTROL(dev)) @@ -390,7 +389,6 @@ static int init_bsd_ring(struct drm_device *dev, static u32 bsd_ring_add_request(struct drm_device *dev, struct intel_ring_buffer *ring, - struct drm_file *file_priv, u32 flush_domains) { u32 seqno; @@ -432,8 +430,8 @@ bsd_ring_put_user_irq(struct drm_device *dev, } static u32 -bsd_ring_get_gem_seqno(struct drm_device *dev, - struct intel_ring_buffer *ring) +bsd_ring_get_seqno(struct drm_device *dev, + struct intel_ring_buffer *ring) { return intel_read_status_page(ring, I915_GEM_HWS_INDEX); } @@ -773,7 +771,7 @@ static const struct intel_ring_buffer render_ring = { .get_active_head = render_ring_get_active_head, .flush = render_ring_flush, .add_request = render_ring_add_request, - .get_gem_seqno = render_ring_get_gem_seqno, + .get_seqno = render_ring_get_seqno, .user_irq_get = render_ring_get_user_irq, .user_irq_put = render_ring_put_user_irq, .dispatch_gem_execbuffer = render_ring_dispatch_gem_execbuffer, @@ -792,7 +790,7 @@ static const struct intel_ring_buffer bsd_ring = { .get_active_head = bsd_ring_get_active_head, .flush = bsd_ring_flush, .add_request = bsd_ring_add_request, - .get_gem_seqno = bsd_ring_get_gem_seqno, + .get_seqno = bsd_ring_get_seqno, .user_irq_get = bsd_ring_get_user_irq, .user_irq_put = bsd_ring_put_user_irq, .dispatch_gem_execbuffer = bsd_ring_dispatch_gem_execbuffer, @@ -883,7 +881,7 @@ static const struct intel_ring_buffer gen6_bsd_ring = { .get_active_head = gen6_bsd_ring_get_active_head, .flush = gen6_bsd_ring_flush, .add_request = bsd_ring_add_request, - .get_gem_seqno = bsd_ring_get_gem_seqno, + .get_seqno = bsd_ring_get_seqno, .user_irq_get = bsd_ring_get_user_irq, .user_irq_put = bsd_ring_put_user_irq, .dispatch_gem_execbuffer = gen6_bsd_ring_dispatch_gem_execbuffer, diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.h b/drivers/gpu/drm/i915/intel_ringbuffer.h index ce52101..d506da1 100644 --- a/drivers/gpu/drm/i915/intel_ringbuffer.h +++ b/drivers/gpu/drm/i915/intel_ringbuffer.h @@ -58,10 +58,9 @@ struct intel_ring_buffer { u32 flush_domains); u32 (*add_request)(struct drm_device *dev, struct intel_ring_buffer *ring, - struct drm_file *file_priv, u32 flush_domains); - u32 (*get_gem_seqno)(struct drm_device *dev, - struct intel_ring_buffer *ring); + u32 (*get_seqno)(struct drm_device *dev, + struct intel_ring_buffer *ring); int (*dispatch_gem_execbuffer)(struct drm_device *dev, struct intel_ring_buffer *ring, struct drm_i915_gem_execbuffer2 *exec, -- cgit v1.1 From 30dbf0c07ff4e3e21b827e2a9d6ff7eb34458819 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Sat, 25 Sep 2010 10:19:17 +0100 Subject: drm/i915: Adjust hangcheck EIO semantics Owain Ainsworth reported an issue between the interaction of the hangcheck and userspace immediately (and permanently) falling back to s/w rasterisation. In order to break the mutex and begin resetting the GPU, we must abort the current operation (usually within the wait) and climb sufficiently far back up the call chain to drop the mutex. In his implementation, Owain has a loop within the ioctl handler to detect the hang and then sleep until the error handler has run. I've chosen to return to userspace and report an EAGAIN which should trigger the userspace ioctl handler to repeat the call (simply because it felt less invasive...). Before hitting a wedged GPU, we then wait upon completion of the error handler. Reported-by: Owain G. Ainsworth Signed-off-by: Chris Wilson --- drivers/gpu/drm/i915/i915_drv.h | 2 ++ drivers/gpu/drm/i915/i915_gem.c | 66 ++++++++++++++++++++++++++++++---- drivers/gpu/drm/i915/i915_gem_tiling.c | 6 +++- drivers/gpu/drm/i915/i915_irq.c | 2 ++ 4 files changed, 68 insertions(+), 8 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 2611e85b..f2ff258 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -363,6 +363,7 @@ typedef struct drm_i915_private { spinlock_t error_lock; struct drm_i915_error_state *first_error; struct work_struct error_work; + struct completion error_completion; struct workqueue_struct *wq; /* Display functions */ @@ -957,6 +958,7 @@ extern void i915_mem_takedown(struct mem_block **heap); extern void i915_mem_release(struct drm_device * dev, struct drm_file *file_priv, struct mem_block *heap); /* i915_gem.c */ +int i915_gem_check_is_wedged(struct drm_device *dev); int i915_gem_init_ioctl(struct drm_device *dev, void *data, struct drm_file *file_priv); int i915_gem_create_ioctl(struct drm_device *dev, void *data, diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index 9185f09..a728309 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -61,6 +61,37 @@ static void i915_gem_free_object_tail(struct drm_gem_object *obj); static LIST_HEAD(shrink_list); static DEFINE_SPINLOCK(shrink_list_lock); +int +i915_gem_check_is_wedged(struct drm_device *dev) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + struct completion *x = &dev_priv->error_completion; + unsigned long flags; + int ret; + + if (!atomic_read(&dev_priv->mm.wedged)) + return 0; + + ret = wait_for_completion_interruptible(x); + if (ret) + return ret; + + /* Success, we reset the GPU! */ + if (!atomic_read(&dev_priv->mm.wedged)) + return 0; + + /* GPU is hung, bump the completion count to account for + * the token we just consumed so that we never hit zero and + * end up waiting upon a subsequent completion event that + * will never happen. + */ + spin_lock_irqsave(&x->wait.lock, flags); + x->done++; + spin_unlock_irqrestore(&x->wait.lock, flags); + return -EIO; +} + + static inline bool i915_gem_object_is_inactive(struct drm_i915_gem_object *obj_priv) { @@ -1848,15 +1879,15 @@ i915_do_wait_request(struct drm_device *dev, uint32_t seqno, BUG_ON(seqno == 0); + if (atomic_read(&dev_priv->mm.wedged)) + return -EAGAIN; + if (seqno == dev_priv->next_seqno) { seqno = i915_add_request(dev, NULL, NULL, ring); if (seqno == 0) return -ENOMEM; } - if (atomic_read(&dev_priv->mm.wedged)) - return -EIO; - if (!i915_seqno_passed(ring->get_seqno(dev, ring), seqno)) { if (HAS_PCH_SPLIT(dev)) ier = I915_READ(DEIER) | I915_READ(GTIER); @@ -1890,7 +1921,7 @@ i915_do_wait_request(struct drm_device *dev, uint32_t seqno, trace_i915_gem_request_wait_end(dev, seqno); } if (atomic_read(&dev_priv->mm.wedged)) - ret = -EIO; + ret = -EAGAIN; if (ret && ret != -ERESTARTSYS) DRM_ERROR("%s returns %d (awaiting %d at %d, next %d)\n", @@ -3569,13 +3600,17 @@ i915_gem_do_execbuffer(struct drm_device *dev, void *data, struct drm_clip_rect *cliprects = NULL; struct drm_i915_gem_relocation_entry *relocs = NULL; struct drm_i915_gem_request *request = NULL; - int ret = 0, ret2, i, pinned = 0; + int ret, ret2, i, pinned = 0; uint64_t exec_offset; uint32_t reloc_index; int pin_tries, flips; struct intel_ring_buffer *ring = NULL; + ret = i915_gem_check_is_wedged(dev); + if (ret) + return ret; + #if WATCH_EXEC DRM_INFO("buffers_ptr %d buffer_count %d len %08x\n", (int) args->buffers_ptr, args->buffer_count, args->batch_len); @@ -3639,7 +3674,7 @@ i915_gem_do_execbuffer(struct drm_device *dev, void *data, if (atomic_read(&dev_priv->mm.wedged)) { mutex_unlock(&dev->struct_mutex); - ret = -EIO; + ret = -EAGAIN; goto pre_mutex_err; } @@ -4126,6 +4161,10 @@ i915_gem_pin_ioctl(struct drm_device *dev, void *data, struct drm_i915_gem_object *obj_priv; int ret; + ret = i915_gem_check_is_wedged(dev); + if (ret) + return ret; + mutex_lock(&dev->struct_mutex); obj = drm_gem_object_lookup(dev, file_priv, args->handle); @@ -4215,9 +4254,15 @@ int i915_gem_busy_ioctl(struct drm_device *dev, void *data, struct drm_file *file_priv) { + struct drm_i915_private *dev_priv = dev->dev_private; struct drm_i915_gem_busy *args = data; struct drm_gem_object *obj; struct drm_i915_gem_object *obj_priv; + int ret; + + ret = i915_gem_check_is_wedged(dev); + if (ret) + return ret; obj = drm_gem_object_lookup(dev, file_priv, args->handle); if (obj == NULL) { @@ -4228,6 +4273,11 @@ i915_gem_busy_ioctl(struct drm_device *dev, void *data, mutex_lock(&dev->struct_mutex); + if (atomic_read(&dev_priv->mm.wedged)) { + ret = -EAGAIN; + goto unlock; + } + /* Count all active objects as busy, even if they are currently not used * by the gpu. Users of this interface expect objects to eventually * become non-busy without any further actions, therefore emit any @@ -4256,9 +4306,10 @@ i915_gem_busy_ioctl(struct drm_device *dev, void *data, args->busy = obj_priv->active; } +unlock: drm_gem_object_unreference(obj); mutex_unlock(&dev->struct_mutex); - return 0; + return ret; } int @@ -4643,6 +4694,7 @@ i915_gem_load(struct drm_device *dev) INIT_LIST_HEAD(&dev_priv->fence_regs[i].lru_list); INIT_DELAYED_WORK(&dev_priv->mm.retire_work, i915_gem_retire_work_handler); + init_completion(&dev_priv->error_completion); spin_lock(&shrink_list_lock); list_add(&dev_priv->mm.shrink_list, &shrink_list); spin_unlock(&shrink_list_lock); diff --git a/drivers/gpu/drm/i915/i915_gem_tiling.c b/drivers/gpu/drm/i915/i915_gem_tiling.c index b09b157..8c9ffc4 100644 --- a/drivers/gpu/drm/i915/i915_gem_tiling.c +++ b/drivers/gpu/drm/i915/i915_gem_tiling.c @@ -273,7 +273,11 @@ i915_gem_set_tiling(struct drm_device *dev, void *data, drm_i915_private_t *dev_priv = dev->dev_private; struct drm_gem_object *obj; struct drm_i915_gem_object *obj_priv; - int ret = 0; + int ret; + + ret = i915_gem_check_is_wedged(dev); + if (ret) + return ret; obj = drm_gem_object_lookup(dev, file_priv, args->handle); if (obj == NULL) diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c index 245a07e..aaa0f1b 100644 --- a/drivers/gpu/drm/i915/i915_irq.c +++ b/drivers/gpu/drm/i915/i915_irq.c @@ -406,6 +406,7 @@ static void i915_error_work_func(struct work_struct *work) atomic_set(&dev_priv->mm.wedged, 0); kobject_uevent_env(&dev->primary->kdev.kobj, KOBJ_CHANGE, reset_done_event); } + complete_all(&dev_priv->error_completion); } } @@ -869,6 +870,7 @@ static void i915_handle_error(struct drm_device *dev, bool wedged) i915_report_and_clear_eir(dev); if (wedged) { + INIT_COMPLETION(dev_priv->error_completion); atomic_set(&dev_priv->mm.wedged, 1); /* -- cgit v1.1 From 76c1dec1979d9b552aab9600eb898ccec394fbbc Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Sat, 25 Sep 2010 11:22:51 +0100 Subject: drm/i915: Make the mutex_lock interruptible on ioctl paths ... and combine it with the wedged completion handler. Signed-off-by: Chris Wilson --- drivers/gpu/drm/i915/i915_gem.c | 126 ++++++++++++++++++++++++++-------------- 1 file changed, 84 insertions(+), 42 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index a728309..ac5bff8 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -91,6 +91,26 @@ i915_gem_check_is_wedged(struct drm_device *dev) return -EIO; } +static int i915_mutex_lock_interruptible(struct drm_device *dev) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + int ret; + + ret = i915_gem_check_is_wedged(dev); + if (ret) + return ret; + + ret = mutex_lock_interruptible(&dev->struct_mutex); + if (ret) + return ret; + + if (atomic_read(&dev_priv->mm.wedged)) { + mutex_unlock(&dev->struct_mutex); + return -EAGAIN; + } + + return 0; +} static inline bool i915_gem_object_is_inactive(struct drm_i915_gem_object *obj_priv) @@ -299,7 +319,9 @@ i915_gem_shmem_pread_fast(struct drm_device *dev, struct drm_gem_object *obj, user_data = (char __user *) (uintptr_t) args->data_ptr; remain = args->size; - mutex_lock(&dev->struct_mutex); + ret = i915_mutex_lock_interruptible(dev); + if (ret) + return ret; ret = i915_gem_object_get_pages(obj, 0); if (ret != 0) @@ -418,7 +440,9 @@ i915_gem_shmem_pread_slow(struct drm_device *dev, struct drm_gem_object *obj, do_bit17_swizzling = i915_gem_object_needs_bit17_swizzle(obj); - mutex_lock(&dev->struct_mutex); + ret = i915_mutex_lock_interruptible(dev); + if (ret) + goto fail_put_user_pages; ret = i915_gem_object_get_pages_or_evict(obj); if (ret) @@ -617,8 +641,10 @@ i915_gem_gtt_pwrite_fast(struct drm_device *dev, struct drm_gem_object *obj, if (!access_ok(VERIFY_READ, user_data, remain)) return -EFAULT; + ret = i915_mutex_lock_interruptible(dev); + if (ret) + return ret; - mutex_lock(&dev->struct_mutex); ret = i915_gem_object_pin(obj, 0); if (ret) { mutex_unlock(&dev->struct_mutex); @@ -713,7 +739,10 @@ i915_gem_gtt_pwrite_slow(struct drm_device *dev, struct drm_gem_object *obj, goto out_unpin_pages; } - mutex_lock(&dev->struct_mutex); + ret = i915_mutex_lock_interruptible(dev); + if (ret) + goto out_unpin_pages; + ret = i915_gem_object_pin(obj, 0); if (ret) goto out_unlock; @@ -787,7 +816,9 @@ i915_gem_shmem_pwrite_fast(struct drm_device *dev, struct drm_gem_object *obj, user_data = (char __user *) (uintptr_t) args->data_ptr; remain = args->size; - mutex_lock(&dev->struct_mutex); + ret = i915_mutex_lock_interruptible(dev); + if (ret) + return ret; ret = i915_gem_object_get_pages(obj, 0); if (ret != 0) @@ -883,7 +914,9 @@ i915_gem_shmem_pwrite_slow(struct drm_device *dev, struct drm_gem_object *obj, do_bit17_swizzling = i915_gem_object_needs_bit17_swizzle(obj); - mutex_lock(&dev->struct_mutex); + ret = i915_mutex_lock_interruptible(dev); + if (ret) + goto fail_put_user_pages; ret = i915_gem_object_get_pages_or_evict(obj); if (ret) @@ -1051,7 +1084,11 @@ i915_gem_set_domain_ioctl(struct drm_device *dev, void *data, return -ENOENT; obj_priv = to_intel_bo(obj); - mutex_lock(&dev->struct_mutex); + ret = i915_mutex_lock_interruptible(dev); + if (ret) { + drm_gem_object_unreference_unlocked(obj); + return ret; + } intel_mark_busy(dev, obj); @@ -1106,11 +1143,14 @@ i915_gem_sw_finish_ioctl(struct drm_device *dev, void *data, if (!(dev->driver->driver_features & DRIVER_GEM)) return -ENODEV; - mutex_lock(&dev->struct_mutex); obj = drm_gem_object_lookup(dev, file_priv, args->handle); - if (obj == NULL) { - mutex_unlock(&dev->struct_mutex); + if (obj == NULL) return -ENOENT; + + ret = i915_mutex_lock_interruptible(dev); + if (ret) { + drm_gem_object_unreference_unlocked(obj); + return ret; } #if WATCH_BUF @@ -1425,7 +1465,11 @@ i915_gem_mmap_gtt_ioctl(struct drm_device *dev, void *data, if (obj == NULL) return -ENOENT; - mutex_lock(&dev->struct_mutex); + ret = i915_mutex_lock_interruptible(dev); + if (ret) { + drm_gem_object_unreference_unlocked(obj); + return ret; + } obj_priv = to_intel_bo(obj); @@ -3668,16 +3712,12 @@ i915_gem_do_execbuffer(struct drm_device *dev, void *data, if (ret != 0) goto pre_mutex_err; - mutex_lock(&dev->struct_mutex); + ret = i915_mutex_lock_interruptible(dev); + if (ret) + goto pre_mutex_err; i915_verify_inactive(dev, __FILE__, __LINE__); - if (atomic_read(&dev_priv->mm.wedged)) { - mutex_unlock(&dev->struct_mutex); - ret = -EAGAIN; - goto pre_mutex_err; - } - if (dev_priv->mm.suspended) { mutex_unlock(&dev->struct_mutex); ret = -EBUSY; @@ -4161,21 +4201,20 @@ i915_gem_pin_ioctl(struct drm_device *dev, void *data, struct drm_i915_gem_object *obj_priv; int ret; - ret = i915_gem_check_is_wedged(dev); - if (ret) - return ret; - - mutex_lock(&dev->struct_mutex); - obj = drm_gem_object_lookup(dev, file_priv, args->handle); if (obj == NULL) { DRM_ERROR("Bad handle in i915_gem_pin_ioctl(): %d\n", args->handle); - mutex_unlock(&dev->struct_mutex); return -ENOENT; } obj_priv = to_intel_bo(obj); + ret = i915_mutex_lock_interruptible(dev); + if (ret) { + drm_gem_object_unreference_unlocked(obj); + return ret; + } + if (obj_priv->madv != I915_MADV_WILLNEED) { DRM_ERROR("Attempting to pin a purgeable buffer\n"); drm_gem_object_unreference(obj); @@ -4220,18 +4259,23 @@ i915_gem_unpin_ioctl(struct drm_device *dev, void *data, struct drm_i915_gem_pin *args = data; struct drm_gem_object *obj; struct drm_i915_gem_object *obj_priv; - - mutex_lock(&dev->struct_mutex); + int ret; obj = drm_gem_object_lookup(dev, file_priv, args->handle); if (obj == NULL) { DRM_ERROR("Bad handle in i915_gem_unpin_ioctl(): %d\n", args->handle); - mutex_unlock(&dev->struct_mutex); return -ENOENT; } obj_priv = to_intel_bo(obj); + + ret = i915_mutex_lock_interruptible(dev); + if (ret) { + drm_gem_object_unreference_unlocked(obj); + return ret; + } + if (obj_priv->pin_filp != file_priv) { DRM_ERROR("Not pinned by caller in i915_gem_pin_ioctl(): %d\n", args->handle); @@ -4254,16 +4298,11 @@ int i915_gem_busy_ioctl(struct drm_device *dev, void *data, struct drm_file *file_priv) { - struct drm_i915_private *dev_priv = dev->dev_private; struct drm_i915_gem_busy *args = data; struct drm_gem_object *obj; struct drm_i915_gem_object *obj_priv; int ret; - ret = i915_gem_check_is_wedged(dev); - if (ret) - return ret; - obj = drm_gem_object_lookup(dev, file_priv, args->handle); if (obj == NULL) { DRM_ERROR("Bad handle in i915_gem_busy_ioctl(): %d\n", @@ -4271,11 +4310,10 @@ i915_gem_busy_ioctl(struct drm_device *dev, void *data, return -ENOENT; } - mutex_lock(&dev->struct_mutex); - - if (atomic_read(&dev_priv->mm.wedged)) { - ret = -EAGAIN; - goto unlock; + ret = i915_mutex_lock_interruptible(dev); + if (ret) { + drm_gem_object_unreference_unlocked(obj); + return ret; } /* Count all active objects as busy, even if they are currently not used @@ -4306,10 +4344,9 @@ i915_gem_busy_ioctl(struct drm_device *dev, void *data, args->busy = obj_priv->active; } -unlock: drm_gem_object_unreference(obj); mutex_unlock(&dev->struct_mutex); - return ret; + return 0; } int @@ -4326,6 +4363,7 @@ i915_gem_madvise_ioctl(struct drm_device *dev, void *data, struct drm_i915_gem_madvise *args = data; struct drm_gem_object *obj; struct drm_i915_gem_object *obj_priv; + int ret; switch (args->madv) { case I915_MADV_DONTNEED: @@ -4341,10 +4379,14 @@ i915_gem_madvise_ioctl(struct drm_device *dev, void *data, args->handle); return -ENOENT; } - - mutex_lock(&dev->struct_mutex); obj_priv = to_intel_bo(obj); + ret = i915_mutex_lock_interruptible(dev); + if (ret) { + drm_gem_object_unreference_unlocked(obj); + return ret; + } + if (obj_priv->pin_count) { drm_gem_object_unreference(obj); mutex_unlock(&dev->struct_mutex); -- cgit v1.1 From 95375b7f9de429100b6e72df5c3abd9a3aaf266c Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Fri, 24 Sep 2010 20:54:39 +0200 Subject: drm/i915: kill now unnecessary gtt defines from i915_reg.h Everything is now handled in intel-gtt.h so these defines are only confusing. Signed-off-by: Daniel Vetter Signed-off-by: Chris Wilson --- drivers/gpu/drm/i915/i915_reg.h | 42 ++--------------------------------------- 1 file changed, 2 insertions(+), 40 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index 77c9191..605db64 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -30,49 +30,11 @@ /* * The Bridge device's PCI config space has information about the * fb aperture size and the amount of pre-reserved memory. + * This is all handled in the intel-gtt.ko module. i915.ko only + * cares about the vga bit for the vga rbiter. */ #define INTEL_GMCH_CTRL 0x52 #define INTEL_GMCH_VGA_DISABLE (1 << 1) -#define INTEL_GMCH_ENABLED 0x4 -#define INTEL_GMCH_MEM_MASK 0x1 -#define INTEL_GMCH_MEM_64M 0x1 -#define INTEL_GMCH_MEM_128M 0 - -#define INTEL_GMCH_GMS_MASK (0xf << 4) -#define INTEL_855_GMCH_GMS_DISABLED (0x0 << 4) -#define INTEL_855_GMCH_GMS_STOLEN_1M (0x1 << 4) -#define INTEL_855_GMCH_GMS_STOLEN_4M (0x2 << 4) -#define INTEL_855_GMCH_GMS_STOLEN_8M (0x3 << 4) -#define INTEL_855_GMCH_GMS_STOLEN_16M (0x4 << 4) -#define INTEL_855_GMCH_GMS_STOLEN_32M (0x5 << 4) - -#define INTEL_915G_GMCH_GMS_STOLEN_48M (0x6 << 4) -#define INTEL_915G_GMCH_GMS_STOLEN_64M (0x7 << 4) -#define INTEL_GMCH_GMS_STOLEN_128M (0x8 << 4) -#define INTEL_GMCH_GMS_STOLEN_256M (0x9 << 4) -#define INTEL_GMCH_GMS_STOLEN_96M (0xa << 4) -#define INTEL_GMCH_GMS_STOLEN_160M (0xb << 4) -#define INTEL_GMCH_GMS_STOLEN_224M (0xc << 4) -#define INTEL_GMCH_GMS_STOLEN_352M (0xd << 4) - -#define SNB_GMCH_CTRL 0x50 -#define SNB_GMCH_GMS_STOLEN_MASK 0xF8 -#define SNB_GMCH_GMS_STOLEN_32M (1 << 3) -#define SNB_GMCH_GMS_STOLEN_64M (2 << 3) -#define SNB_GMCH_GMS_STOLEN_96M (3 << 3) -#define SNB_GMCH_GMS_STOLEN_128M (4 << 3) -#define SNB_GMCH_GMS_STOLEN_160M (5 << 3) -#define SNB_GMCH_GMS_STOLEN_192M (6 << 3) -#define SNB_GMCH_GMS_STOLEN_224M (7 << 3) -#define SNB_GMCH_GMS_STOLEN_256M (8 << 3) -#define SNB_GMCH_GMS_STOLEN_288M (9 << 3) -#define SNB_GMCH_GMS_STOLEN_320M (0xa << 3) -#define SNB_GMCH_GMS_STOLEN_352M (0xb << 3) -#define SNB_GMCH_GMS_STOLEN_384M (0xc << 3) -#define SNB_GMCH_GMS_STOLEN_416M (0xd << 3) -#define SNB_GMCH_GMS_STOLEN_448M (0xe << 3) -#define SNB_GMCH_GMS_STOLEN_480M (0xf << 3) -#define SNB_GMCH_GMS_STOLEN_512M (0x10 << 3) /* PCI config space */ -- cgit v1.1 From bf7e0e1268f72ea1687140603a910eeaca031fa1 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Fri, 24 Sep 2010 21:08:29 +0200 Subject: drm/i915: fix ACTHD for gen <= 3 This was mixed up in the following patch: commit a6c45cf013a57e32ddae43dd4ac911eb4a3919fd Author: Chris Wilson Date: Fri Sep 17 00:32:17 2010 +0100 drm/i915: INTEL_INFO->gen supercedes i8xx, i9xx, i965g Signed-off-by: Daniel Vetter Signed-off-by: Chris Wilson --- drivers/gpu/drm/i915/intel_ringbuffer.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.c b/drivers/gpu/drm/i915/intel_ringbuffer.c index 9b848be..ede436b 100644 --- a/drivers/gpu/drm/i915/intel_ringbuffer.c +++ b/drivers/gpu/drm/i915/intel_ringbuffer.c @@ -131,7 +131,7 @@ static unsigned int render_ring_get_active_head(struct drm_device *dev, struct intel_ring_buffer *ring) { drm_i915_private_t *dev_priv = dev->dev_private; - u32 acthd_reg = INTEL_INFO(dev)->gen ? ACTHD_I965 : ACTHD; + u32 acthd_reg = INTEL_INFO(dev)->gen >= 4 ? ACTHD_I965 : ACTHD; return I915_READ(acthd_reg); } -- cgit v1.1 From 3d281d8cca1acb2483444e0d1519c8ab6dda3a47 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Fri, 24 Sep 2010 21:14:22 +0200 Subject: drm/i915: kill per-ring macros Two macros that use a base address for HWS_PGA were missing, add them. Also switch the remaining users of *_ACTHD to the ring-base one. Kill the other ring-specific macros because they're now unused. Signed-off-by: Daniel Vetter [ickle: And silence checkpatch whilst in the vicinity] Signed-off-by: Chris Wilson --- drivers/gpu/drm/i915/i915_reg.h | 35 +++++++-------------------------- drivers/gpu/drm/i915/intel_ringbuffer.c | 25 ++++++++++++----------- 2 files changed, 21 insertions(+), 39 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index 605db64..ddbcd8c 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -253,11 +253,13 @@ #define RENDER_RING_BASE 0x02000 #define BSD_RING_BASE 0x04000 #define GEN6_BSD_RING_BASE 0x12000 -#define RING_TAIL(base) (base)+0x30 -#define RING_HEAD(base) (base)+0x34 -#define RING_START(base) (base)+0x38 -#define RING_CTL(base) (base)+0x3c -#define RING_HWS_PGA(base) (base)+0x80 +#define RING_TAIL(base) ((base)+0x30) +#define RING_HEAD(base) ((base)+0x34) +#define RING_START(base) ((base)+0x38) +#define RING_CTL(base) ((base)+0x3c) +#define RING_HWS_PGA(base) ((base)+0x80) +#define RING_HWS_PGA_GEN6(base) ((base)+0x2080) +#define RING_ACTHD(base) ((base)+0x74) #define TAIL_ADDR 0x001FFFF8 #define HEAD_WRAP_COUNT 0xFFE00000 #define HEAD_WRAP_ONE 0x00200000 @@ -283,7 +285,6 @@ #define INSTDONE1 0x0207c /* 965+ only */ #define ACTHD_I965 0x02074 #define HWS_PGA 0x02080 -#define HWS_PGA_GEN6 0x04080 #define HWS_ADDRESS_MASK 0xfffff000 #define HWS_START_ADDRESS_SHIFT 4 #define PWRCTXA 0x2088 /* 965GM+ only */ @@ -441,28 +442,6 @@ #define GEN6_BLITTER_COMMAND_PARSER_MASTER_ERROR (1 << 25) #define GEN6_BLITTER_SYNC_STATUS (1 << 24) #define GEN6_BLITTER_USER_INTERRUPT (1 << 22) -/* - * BSD (bit stream decoder instruction and interrupt control register defines - * (G4X and Ironlake only) - */ - -#define BSD_RING_TAIL 0x04030 -#define BSD_RING_HEAD 0x04034 -#define BSD_RING_START 0x04038 -#define BSD_RING_CTL 0x0403c -#define BSD_RING_ACTHD 0x04074 -#define BSD_HWS_PGA 0x04080 - -/* - * video command stream instruction and interrupt control register defines - * for GEN6 - */ -#define GEN6_BSD_RING_TAIL 0x12030 -#define GEN6_BSD_RING_HEAD 0x12034 -#define GEN6_BSD_RING_START 0x12038 -#define GEN6_BSD_RING_CTL 0x1203c -#define GEN6_BSD_RING_ACTHD 0x12074 -#define GEN6_BSD_HWS_PGA 0x14080 #define GEN6_BSD_SLEEP_PSMI_CONTROL 0x12050 #define GEN6_BSD_SLEEP_PSMI_CONTROL_RC_ILDL_MESSAGE_MODIFY_MASK (1 << 16) diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.c b/drivers/gpu/drm/i915/intel_ringbuffer.c index ede436b..487575f 100644 --- a/drivers/gpu/drm/i915/intel_ringbuffer.c +++ b/drivers/gpu/drm/i915/intel_ringbuffer.c @@ -131,7 +131,8 @@ static unsigned int render_ring_get_active_head(struct drm_device *dev, struct intel_ring_buffer *ring) { drm_i915_private_t *dev_priv = dev->dev_private; - u32 acthd_reg = INTEL_INFO(dev)->gen >= 4 ? ACTHD_I965 : ACTHD; + u32 acthd_reg = INTEL_INFO(dev)->gen >= 4 ? + RING_ACTHD(ring->mmio_base) : ACTHD; return I915_READ(acthd_reg); } @@ -352,11 +353,13 @@ static void render_setup_status_page(struct drm_device *dev, { drm_i915_private_t *dev_priv = dev->dev_private; if (IS_GEN6(dev)) { - I915_WRITE(HWS_PGA_GEN6, ring->status_page.gfx_addr); - I915_READ(HWS_PGA_GEN6); /* posting read */ + I915_WRITE(RING_HWS_PGA_GEN6(ring->mmio_base), + ring->status_page.gfx_addr); + I915_READ(RING_HWS_PGA_GEN6(ring->mmio_base)); /* posting read */ } else { - I915_WRITE(HWS_PGA, ring->status_page.gfx_addr); - I915_READ(HWS_PGA); /* posting read */ + I915_WRITE(RING_HWS_PGA(ring->mmio_base), + ring->status_page.gfx_addr); + I915_READ(RING_HWS_PGA(ring->mmio_base)); /* posting read */ } } @@ -377,7 +380,7 @@ static unsigned int bsd_ring_get_active_head(struct drm_device *dev, struct intel_ring_buffer *ring) { drm_i915_private_t *dev_priv = dev->dev_private; - return I915_READ(BSD_RING_ACTHD); + return I915_READ(RING_ACTHD(ring->mmio_base)); } static int init_bsd_ring(struct drm_device *dev, @@ -412,8 +415,8 @@ static void bsd_setup_status_page(struct drm_device *dev, struct intel_ring_buffer *ring) { drm_i915_private_t *dev_priv = dev->dev_private; - I915_WRITE(BSD_HWS_PGA, ring->status_page.gfx_addr); - I915_READ(BSD_HWS_PGA); + I915_WRITE(RING_HWS_PGA(ring->mmio_base), ring->status_page.gfx_addr); + I915_READ(RING_HWS_PGA(ring->mmio_base)); } static void @@ -801,8 +804,8 @@ static void gen6_bsd_setup_status_page(struct drm_device *dev, struct intel_ring_buffer *ring) { drm_i915_private_t *dev_priv = dev->dev_private; - I915_WRITE(GEN6_BSD_HWS_PGA, ring->status_page.gfx_addr); - I915_READ(GEN6_BSD_HWS_PGA); + I915_WRITE(RING_HWS_PGA_GEN6(ring->mmio_base), ring->status_page.gfx_addr); + I915_READ(RING_HWS_PGA_GEN6(ring->mmio_base)); } static void gen6_bsd_ring_set_tail(struct drm_device *dev, @@ -832,7 +835,7 @@ static unsigned int gen6_bsd_ring_get_active_head(struct drm_device *dev, struct intel_ring_buffer *ring) { drm_i915_private_t *dev_priv = dev->dev_private; - return I915_READ(GEN6_BSD_RING_ACTHD); + return I915_READ(RING_ACTHD(ring->mmio_base)); } static void gen6_bsd_ring_flush(struct drm_device *dev, -- cgit v1.1 From 79f321b7e676bd54f563c5ce513588aa90b2cc21 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Fri, 24 Sep 2010 21:20:10 +0200 Subject: drm/i915: kill ring->get_active_head All functions are extremely similar, so fold them into one generic implementation. This function isn't used anyway, because there's not yet a bsd ring error state dumper. Signed-off-by: Daniel Vetter Signed-off-by: Chris Wilson --- drivers/gpu/drm/i915/intel_ringbuffer.c | 21 ++------------------- drivers/gpu/drm/i915/intel_ringbuffer.h | 5 +++-- 2 files changed, 5 insertions(+), 21 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.c b/drivers/gpu/drm/i915/intel_ringbuffer.c index 487575f..a3e73d4 100644 --- a/drivers/gpu/drm/i915/intel_ringbuffer.c +++ b/drivers/gpu/drm/i915/intel_ringbuffer.c @@ -127,8 +127,8 @@ static void ring_set_tail(struct drm_device *dev, I915_WRITE_TAIL(ring, ring->tail); } -static unsigned int render_ring_get_active_head(struct drm_device *dev, - struct intel_ring_buffer *ring) +u32 intel_ring_get_active_head(struct drm_device *dev, + struct intel_ring_buffer *ring) { drm_i915_private_t *dev_priv = dev->dev_private; u32 acthd_reg = INTEL_INFO(dev)->gen >= 4 ? @@ -376,13 +376,6 @@ bsd_ring_flush(struct drm_device *dev, intel_ring_advance(dev, ring); } -static unsigned int bsd_ring_get_active_head(struct drm_device *dev, - struct intel_ring_buffer *ring) -{ - drm_i915_private_t *dev_priv = dev->dev_private; - return I915_READ(RING_ACTHD(ring->mmio_base)); -} - static int init_bsd_ring(struct drm_device *dev, struct intel_ring_buffer *ring) { @@ -771,7 +764,6 @@ static const struct intel_ring_buffer render_ring = { .setup_status_page = render_setup_status_page, .init = init_render_ring, .set_tail = ring_set_tail, - .get_active_head = render_ring_get_active_head, .flush = render_ring_flush, .add_request = render_ring_add_request, .get_seqno = render_ring_get_seqno, @@ -790,7 +782,6 @@ static const struct intel_ring_buffer bsd_ring = { .setup_status_page = bsd_setup_status_page, .init = init_bsd_ring, .set_tail = ring_set_tail, - .get_active_head = bsd_ring_get_active_head, .flush = bsd_ring_flush, .add_request = bsd_ring_add_request, .get_seqno = bsd_ring_get_seqno, @@ -831,13 +822,6 @@ static void gen6_bsd_ring_set_tail(struct drm_device *dev, GEN6_BSD_SLEEP_PSMI_CONTROL_RC_ILDL_MESSAGE_ENABLE); } -static unsigned int gen6_bsd_ring_get_active_head(struct drm_device *dev, - struct intel_ring_buffer *ring) -{ - drm_i915_private_t *dev_priv = dev->dev_private; - return I915_READ(RING_ACTHD(ring->mmio_base)); -} - static void gen6_bsd_ring_flush(struct drm_device *dev, struct intel_ring_buffer *ring, u32 invalidate_domains, @@ -881,7 +865,6 @@ static const struct intel_ring_buffer gen6_bsd_ring = { .setup_status_page = gen6_bsd_setup_status_page, .init = init_bsd_ring, .set_tail = gen6_bsd_ring_set_tail, - .get_active_head = gen6_bsd_ring_get_active_head, .flush = gen6_bsd_ring_flush, .add_request = bsd_ring_add_request, .get_seqno = bsd_ring_get_seqno, diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.h b/drivers/gpu/drm/i915/intel_ringbuffer.h index d506da1..43c5f7a 100644 --- a/drivers/gpu/drm/i915/intel_ringbuffer.h +++ b/drivers/gpu/drm/i915/intel_ringbuffer.h @@ -50,8 +50,6 @@ struct intel_ring_buffer { void (*set_tail)(struct drm_device *dev, struct intel_ring_buffer *ring, u32 value); - unsigned int (*get_active_head)(struct drm_device *dev, - struct intel_ring_buffer *ring); void (*flush)(struct drm_device *dev, struct intel_ring_buffer *ring, u32 invalidate_domains, @@ -128,4 +126,7 @@ u32 intel_ring_get_seqno(struct drm_device *dev, int intel_init_render_ring_buffer(struct drm_device *dev); int intel_init_bsd_ring_buffer(struct drm_device *dev); +u32 intel_ring_get_active_head(struct drm_device *dev, + struct intel_ring_buffer *ring); + #endif /* _INTEL_RINGBUFFER_H_ */ -- cgit v1.1 From 447da18742b170b8e09ac71edf63c5798d2dbb0b Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Fri, 24 Sep 2010 21:49:27 +0200 Subject: drm/i915: kill ring->setup_status_page It's the same code, essentially, so kill all copies safe one unified version. Signed-off-by: Daniel Vetter Signed-off-by: Chris Wilson --- drivers/gpu/drm/i915/i915_dma.c | 2 +- drivers/gpu/drm/i915/intel_ringbuffer.c | 25 +++---------------------- drivers/gpu/drm/i915/intel_ringbuffer.h | 4 ++-- 3 files changed, 6 insertions(+), 25 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_dma.c b/drivers/gpu/drm/i915/i915_dma.c index a3aea17..ba050ed 100644 --- a/drivers/gpu/drm/i915/i915_dma.c +++ b/drivers/gpu/drm/i915/i915_dma.c @@ -221,7 +221,7 @@ static int i915_dma_resume(struct drm_device * dev) DRM_DEBUG_DRIVER("hw status page @ %p\n", ring->status_page.page_addr); if (ring->status_page.gfx_addr != 0) - ring->setup_status_page(dev, ring); + intel_ring_setup_status_page(dev, ring); else I915_WRITE(HWS_PGA, dev_priv->dma_status_page); diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.c b/drivers/gpu/drm/i915/intel_ringbuffer.c index a3e73d4..5103b95 100644 --- a/drivers/gpu/drm/i915/intel_ringbuffer.c +++ b/drivers/gpu/drm/i915/intel_ringbuffer.c @@ -348,8 +348,8 @@ render_ring_put_user_irq(struct drm_device *dev, spin_unlock_irqrestore(&dev_priv->user_irq_lock, irqflags); } -static void render_setup_status_page(struct drm_device *dev, - struct intel_ring_buffer *ring) +void intel_ring_setup_status_page(struct drm_device *dev, + struct intel_ring_buffer *ring) { drm_i915_private_t *dev_priv = dev->dev_private; if (IS_GEN6(dev)) { @@ -404,14 +404,6 @@ bsd_ring_add_request(struct drm_device *dev, return seqno; } -static void bsd_setup_status_page(struct drm_device *dev, - struct intel_ring_buffer *ring) -{ - drm_i915_private_t *dev_priv = dev->dev_private; - I915_WRITE(RING_HWS_PGA(ring->mmio_base), ring->status_page.gfx_addr); - I915_READ(RING_HWS_PGA(ring->mmio_base)); -} - static void bsd_ring_get_user_irq(struct drm_device *dev, struct intel_ring_buffer *ring) @@ -564,7 +556,7 @@ static int init_status_page(struct drm_device *dev, ring->status_page.obj = obj; memset(ring->status_page.page_addr, 0, PAGE_SIZE); - ring->setup_status_page(dev, ring); + intel_ring_setup_status_page(dev, ring); DRM_DEBUG_DRIVER("%s hws offset: 0x%08x\n", ring->name, ring->status_page.gfx_addr); @@ -761,7 +753,6 @@ static const struct intel_ring_buffer render_ring = { .id = RING_RENDER, .mmio_base = RENDER_RING_BASE, .size = 32 * PAGE_SIZE, - .setup_status_page = render_setup_status_page, .init = init_render_ring, .set_tail = ring_set_tail, .flush = render_ring_flush, @@ -779,7 +770,6 @@ static const struct intel_ring_buffer bsd_ring = { .id = RING_BSD, .mmio_base = BSD_RING_BASE, .size = 32 * PAGE_SIZE, - .setup_status_page = bsd_setup_status_page, .init = init_bsd_ring, .set_tail = ring_set_tail, .flush = bsd_ring_flush, @@ -791,14 +781,6 @@ static const struct intel_ring_buffer bsd_ring = { }; -static void gen6_bsd_setup_status_page(struct drm_device *dev, - struct intel_ring_buffer *ring) -{ - drm_i915_private_t *dev_priv = dev->dev_private; - I915_WRITE(RING_HWS_PGA_GEN6(ring->mmio_base), ring->status_page.gfx_addr); - I915_READ(RING_HWS_PGA_GEN6(ring->mmio_base)); -} - static void gen6_bsd_ring_set_tail(struct drm_device *dev, struct intel_ring_buffer *ring, u32 value) @@ -862,7 +844,6 @@ static const struct intel_ring_buffer gen6_bsd_ring = { .id = RING_BSD, .mmio_base = GEN6_BSD_RING_BASE, .size = 32 * PAGE_SIZE, - .setup_status_page = gen6_bsd_setup_status_page, .init = init_bsd_ring, .set_tail = gen6_bsd_ring_set_tail, .flush = gen6_bsd_ring_flush, diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.h b/drivers/gpu/drm/i915/intel_ringbuffer.h index 43c5f7a..c509192 100644 --- a/drivers/gpu/drm/i915/intel_ringbuffer.h +++ b/drivers/gpu/drm/i915/intel_ringbuffer.h @@ -41,8 +41,6 @@ struct intel_ring_buffer { struct intel_ring_buffer *ring); void (*user_irq_put)(struct drm_device *dev, struct intel_ring_buffer *ring); - void (*setup_status_page)(struct drm_device *dev, - struct intel_ring_buffer *ring); int (*init)(struct drm_device *dev, struct intel_ring_buffer *ring); @@ -128,5 +126,7 @@ int intel_init_bsd_ring_buffer(struct drm_device *dev); u32 intel_ring_get_active_head(struct drm_device *dev, struct intel_ring_buffer *ring); +void intel_ring_setup_status_page(struct drm_device *dev, + struct intel_ring_buffer *ring); #endif /* _INTEL_RINGBUFFER_H_ */ -- cgit v1.1 From 1c25595f8d31392b8c36b54c624d01591dbfb87b Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Sun, 26 Sep 2010 11:03:27 +0100 Subject: drm/i915: Convert the file mutex into a spinlock Daniel Vetter pointed out that in this case is would be clearer and cleaner to use a spinlock instead of a mutex to protect the per-file request list manipulation. Make it so. Signed-off-by: Chris Wilson --- drivers/gpu/drm/i915/i915_dma.c | 2 +- drivers/gpu/drm/i915/i915_drv.h | 2 +- drivers/gpu/drm/i915/i915_gem.c | 28 +++++++++++++++------------- 3 files changed, 17 insertions(+), 15 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_dma.c b/drivers/gpu/drm/i915/i915_dma.c index ba050ed..b752c31 100644 --- a/drivers/gpu/drm/i915/i915_dma.c +++ b/drivers/gpu/drm/i915/i915_dma.c @@ -2173,8 +2173,8 @@ int i915_driver_open(struct drm_device *dev, struct drm_file *file) file->driver_priv = file_priv; + spin_lock_init(&file_priv->mm.lock); INIT_LIST_HEAD(&file_priv->mm.request_list); - mutex_init(&file_priv->mutex); return 0; } diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index f2ff258..710d59e 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -851,8 +851,8 @@ struct drm_i915_gem_request { }; struct drm_i915_file_private { - struct mutex mutex; struct { + struct spinlock lock; struct list_head request_list; } mm; }; diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index ac5bff8..78282ed 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -1694,11 +1694,11 @@ i915_add_request(struct drm_device *dev, list_add_tail(&request->list, &ring->request_list); if (file_priv) { - mutex_lock(&file_priv->mutex); + spin_lock(&file_priv->mm.lock); request->file_priv = file_priv; list_add_tail(&request->client_list, &file_priv->mm.request_list); - mutex_unlock(&file_priv->mutex); + spin_unlock(&file_priv->mm.lock); } if (!dev_priv->mm.suspended) { @@ -1733,11 +1733,15 @@ i915_retire_commands(struct drm_device *dev, struct intel_ring_buffer *ring) static inline void i915_gem_request_remove_from_client(struct drm_i915_gem_request *request) { - if (request->file_priv) { - mutex_lock(&request->file_priv->mutex); - list_del(&request->client_list); - mutex_unlock(&request->file_priv->mutex); - } + struct drm_i915_file_private *file_priv = request->file_priv; + + if (!file_priv) + return; + + spin_lock(&file_priv->mm.lock); + list_del(&request->client_list); + request->file_priv = NULL; + spin_unlock(&file_priv->mm.lock); } static void i915_gem_reset_ring_lists(struct drm_i915_private *dev_priv, @@ -3464,7 +3468,7 @@ i915_gem_ring_throttle(struct drm_device *dev, struct drm_file *file) u32 seqno = 0; int ret; - mutex_lock(&file_priv->mutex); + spin_lock(&file_priv->mm.lock); list_for_each_entry(request, &file_priv->mm.request_list, client_list) { if (time_after_eq(request->emitted_jiffies, recent_enough)) break; @@ -3472,7 +3476,7 @@ i915_gem_ring_throttle(struct drm_device *dev, struct drm_file *file) ring = request->ring; seqno = request->seqno; } - mutex_unlock(&file_priv->mutex); + spin_unlock(&file_priv->mm.lock); if (seqno == 0) return 0; @@ -4974,8 +4978,7 @@ void i915_gem_release(struct drm_device *dev, struct drm_file *file) * later retire_requests won't dereference our soon-to-be-gone * file_priv. */ - mutex_lock(&dev->struct_mutex); - mutex_lock(&file_priv->mutex); + spin_lock(&file_priv->mm.lock); while (!list_empty(&file_priv->mm.request_list)) { struct drm_i915_gem_request *request; @@ -4985,8 +4988,7 @@ void i915_gem_release(struct drm_device *dev, struct drm_file *file) list_del(&request->client_list); request->file_priv = NULL; } - mutex_unlock(&file_priv->mutex); - mutex_unlock(&dev->struct_mutex); + spin_unlock(&file_priv->mm.lock); } static int -- cgit v1.1 From 53b2087d218c100657bddcb8ae887fa07862fb81 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Sun, 26 Sep 2010 22:21:10 +0100 Subject: drm/i915: fix debugging compilation error from previous commit There is no equivalent to mutex_destroy() for spinlocks so just delete the code. Signed-off-by: Chris Wilson --- drivers/gpu/drm/i915/i915_dma.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/gpu/drm/i915/i915_dma.c b/drivers/gpu/drm/i915/i915_dma.c index b752c31..df1c353 100644 --- a/drivers/gpu/drm/i915/i915_dma.c +++ b/drivers/gpu/drm/i915/i915_dma.c @@ -2221,7 +2221,6 @@ void i915_driver_postclose(struct drm_device *dev, struct drm_file *file) { struct drm_i915_file_private *file_priv = file->driver_priv; - mutex_destroy(&file_priv->mutex); kfree(file_priv); } -- cgit v1.1 From ced270fa893735363f74bf96e0a8a05ec330d04d Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Sun, 26 Sep 2010 22:47:46 +0100 Subject: drm/i915: Ensure that the mode change flushing is currently uninterruptible Introduced by 48b956c5, I had thought I had already fixed this. Oh well. Reported-by: Sitsofe Wheeler Signed-off-by: Chris Wilson --- drivers/gpu/drm/i915/i915_gem.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index 78282ed..1025508 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -2858,10 +2858,17 @@ i915_gem_object_set_to_display_plane(struct drm_gem_object *obj, if (obj_priv->gtt_space == NULL) return -EINVAL; - ret = i915_gem_object_flush_gpu_write_domain(obj, pipelined); + ret = i915_gem_object_flush_gpu_write_domain(obj, true); if (ret) return ret; + /* Currently, we are always called from an non-interruptible context. */ + if (!pipelined) { + ret = i915_gem_object_wait_rendering(obj, false); + if (ret) + return ret; + } + i915_gem_object_flush_cpu_write_domain(obj); old_read_domains = obj->read_domains; -- cgit v1.1 From d270ae34eb77c58dea60e5b1e300a698d2ce39ac Mon Sep 17 00:00:00 2001 From: Jesse Barnes Date: Mon, 27 Sep 2010 10:35:44 -0700 Subject: drm/i915: fix GMCH power reporting The IPS driver needs to know the current power consumption of the GMCH in order to make decisions about when to increase or decrease the CPU and/or GPU power envelope. So fix up the divisions to save the results so the numbers are actually correct (contrary to some earlier comments and code, these functions do not modify the first argument and use it for the result). Signed-off-by: Jesse Barnes Signed-off-by: Chris Wilson Cc: stable@kernel.org --- drivers/gpu/drm/i915/i915_dma.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_dma.c b/drivers/gpu/drm/i915/i915_dma.c index 9d67b48..c74e4e8 100644 --- a/drivers/gpu/drm/i915/i915_dma.c +++ b/drivers/gpu/drm/i915/i915_dma.c @@ -1787,9 +1787,9 @@ unsigned long i915_chipset_val(struct drm_i915_private *dev_priv) } } - div_u64(diff, diff1); + diff = div_u64(diff, diff1); ret = ((m * diff) + c); - div_u64(ret, 10); + ret = div_u64(ret, 10); dev_priv->last_count1 = total_count; dev_priv->last_time1 = now; @@ -1858,7 +1858,7 @@ void i915_update_gfx_val(struct drm_i915_private *dev_priv) /* More magic constants... */ diff = diff * 1181; - div_u64(diff, diffms * 10); + diff = div_u64(diff, diffms * 10); dev_priv->gfx_power = diff; } -- cgit v1.1 From a56ba56c275b1c2b982c8901ab92bf5a0fd0b757 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Tue, 28 Sep 2010 10:07:56 +0100 Subject: Revert "drm/i915: Drop ring->lazy_request" With multiple rings generating requests independently, the outstanding requests must also be track independently. Reported-by: Wang Jinjin Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=30380 Signed-off-by: Chris Wilson --- drivers/gpu/drm/i915/i915_gem.c | 43 +++++++++++++++++++++++---------- drivers/gpu/drm/i915/intel_ringbuffer.h | 5 ++++ 2 files changed, 35 insertions(+), 13 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index 1025508..63b3860 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -1545,12 +1545,23 @@ i915_gem_object_put_pages(struct drm_gem_object *obj) obj_priv->pages = NULL; } +static uint32_t +i915_gem_next_request_seqno(struct drm_device *dev, + struct intel_ring_buffer *ring) +{ + drm_i915_private_t *dev_priv = dev->dev_private; + + ring->outstanding_lazy_request = true; + return dev_priv->next_seqno; +} + static void i915_gem_object_move_to_active(struct drm_gem_object *obj, struct intel_ring_buffer *ring) { - struct drm_i915_private *dev_priv = obj->dev->dev_private; + struct drm_device *dev = obj->dev; struct drm_i915_gem_object *obj_priv = to_intel_bo(obj); + uint32_t seqno = i915_gem_next_request_seqno(dev, ring); BUG_ON(ring == NULL); obj_priv->ring = ring; @@ -1563,7 +1574,7 @@ i915_gem_object_move_to_active(struct drm_gem_object *obj, /* Move from whatever list we were on to the tail of execution. */ list_move_tail(&obj_priv->list, &ring->active_list); - obj_priv->last_rendering_seqno = dev_priv->next_seqno; + obj_priv->last_rendering_seqno = seqno; } static void @@ -1686,6 +1697,7 @@ i915_add_request(struct drm_device *dev, } seqno = ring->add_request(dev, ring, 0); + ring->outstanding_lazy_request = false; request->seqno = seqno; request->ring = ring; @@ -1930,11 +1942,12 @@ i915_do_wait_request(struct drm_device *dev, uint32_t seqno, if (atomic_read(&dev_priv->mm.wedged)) return -EAGAIN; - if (seqno == dev_priv->next_seqno) { + if (ring->outstanding_lazy_request) { seqno = i915_add_request(dev, NULL, NULL, ring); if (seqno == 0) return -ENOMEM; } + BUG_ON(seqno == dev_priv->next_seqno); if (!i915_seqno_passed(ring->get_seqno(dev, ring), seqno)) { if (HAS_PCH_SPLIT(dev)) @@ -1993,7 +2006,7 @@ i915_do_wait_request(struct drm_device *dev, uint32_t seqno, */ static int i915_wait_request(struct drm_device *dev, uint32_t seqno, - struct intel_ring_buffer *ring) + struct intel_ring_buffer *ring) { return i915_do_wait_request(dev, seqno, 1, ring); } @@ -2139,12 +2152,21 @@ i915_gem_object_unbind(struct drm_gem_object *obj) return ret; } +static int i915_ring_idle(struct drm_device *dev, + struct intel_ring_buffer *ring) +{ + i915_gem_flush_ring(dev, NULL, ring, + I915_GEM_GPU_DOMAINS, I915_GEM_GPU_DOMAINS); + return i915_wait_request(dev, + i915_gem_next_request_seqno(dev, ring), + ring); +} + int i915_gpu_idle(struct drm_device *dev) { drm_i915_private_t *dev_priv = dev->dev_private; bool lists_empty; - u32 seqno; int ret; lists_empty = (list_empty(&dev_priv->mm.flushing_list) && @@ -2155,18 +2177,12 @@ i915_gpu_idle(struct drm_device *dev) return 0; /* Flush everything onto the inactive list. */ - seqno = dev_priv->next_seqno; - i915_gem_flush_ring(dev, NULL, &dev_priv->render_ring, - I915_GEM_GPU_DOMAINS, I915_GEM_GPU_DOMAINS); - ret = i915_wait_request(dev, seqno, &dev_priv->render_ring); + ret = i915_ring_idle(dev, &dev_priv->render_ring); if (ret) return ret; if (HAS_BSD(dev)) { - seqno = dev_priv->next_seqno; - i915_gem_flush_ring(dev, NULL, &dev_priv->bsd_ring, - I915_GEM_GPU_DOMAINS, I915_GEM_GPU_DOMAINS); - ret = i915_wait_request(dev, seqno, &dev_priv->bsd_ring); + ret = i915_ring_idle(dev, &dev_priv->bsd_ring); if (ret) return ret; } @@ -3938,6 +3954,7 @@ i915_gem_do_execbuffer(struct drm_device *dev, void *data, DRM_INFO("%s: move to exec list %p\n", __func__, obj); #endif } + i915_add_request(dev, file_priv, request, ring); request = NULL; diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.h b/drivers/gpu/drm/i915/intel_ringbuffer.h index c509192..9725f78 100644 --- a/drivers/gpu/drm/i915/intel_ringbuffer.h +++ b/drivers/gpu/drm/i915/intel_ringbuffer.h @@ -81,6 +81,11 @@ struct intel_ring_buffer { */ struct list_head request_list; + /** + * Do we have some not yet emitted requests outstanding? + */ + bool outstanding_lazy_request; + wait_queue_head_t irq_queue; drm_local_map_t map; }; -- cgit v1.1 From e957d7720a2797b31231616014b68f4f6203145e Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Fri, 24 Sep 2010 12:52:03 +0100 Subject: drm/i915/sdvo: Fix GMBUSification Besides a couple of bugs when writing more than a single byte along the GMBUS, SDVO was completely failing whilst trying to use GMBUS, so use bit banging instead. Signed-off-by: Chris Wilson --- drivers/gpu/drm/i915/i915_drv.h | 10 +- drivers/gpu/drm/i915/intel_bios.c | 9 ++ drivers/gpu/drm/i915/intel_bios.h | 3 +- drivers/gpu/drm/i915/intel_i2c.c | 181 ++++++++++++++------- drivers/gpu/drm/i915/intel_sdvo.c | 332 ++++++++++++++++++++++---------------- 5 files changed, 339 insertions(+), 196 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 710d59e..0bb2553 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -132,10 +132,12 @@ struct drm_i915_fence_reg { }; struct sdvo_device_mapping { + u8 initialized; u8 dvo_port; u8 slave_addr; u8 dvo_wiring; - u8 initialized; + u8 i2c_pin; + u8 i2c_speed; u8 ddc_pin; }; @@ -248,8 +250,8 @@ typedef struct drm_i915_private { struct intel_gmbus { struct i2c_adapter adapter; - struct i2c_adapter *force_bitbanging; - int pin; + struct i2c_adapter *force_bit; + u32 reg0; } *gmbus; struct pci_dev *bridge_dev; @@ -1104,6 +1106,8 @@ extern int i915_restore_state(struct drm_device *dev); /* intel_i2c.c */ extern int intel_setup_gmbus(struct drm_device *dev); extern void intel_teardown_gmbus(struct drm_device *dev); +extern void intel_gmbus_set_speed(struct i2c_adapter *adapter, int speed); +extern void intel_gmbus_force_bit(struct i2c_adapter *adapter, bool force_bit); extern void intel_i2c_reset(struct drm_device *dev); /* intel_opregion.c */ diff --git a/drivers/gpu/drm/i915/intel_bios.c b/drivers/gpu/drm/i915/intel_bios.c index 42a7a5b..7e868d2 100644 --- a/drivers/gpu/drm/i915/intel_bios.c +++ b/drivers/gpu/drm/i915/intel_bios.c @@ -369,7 +369,16 @@ parse_sdvo_device_mapping(struct drm_i915_private *dev_priv, p_mapping->slave_addr = p_child->slave_addr; p_mapping->dvo_wiring = p_child->dvo_wiring; p_mapping->ddc_pin = p_child->ddc_pin; + p_mapping->i2c_pin = p_child->i2c_pin; + p_mapping->i2c_speed = p_child->i2c_speed; p_mapping->initialized = 1; + DRM_DEBUG_KMS("SDVO device: dvo=%x, addr=%x, wiring=%d, ddc_pin=%d, i2c_pin=%d, i2c_speed=%d\n", + p_mapping->dvo_port, + p_mapping->slave_addr, + p_mapping->dvo_wiring, + p_mapping->ddc_pin, + p_mapping->i2c_pin, + p_mapping->i2c_speed); } else { DRM_DEBUG_KMS("Maybe one SDVO port is shared by " "two SDVO device.\n"); diff --git a/drivers/gpu/drm/i915/intel_bios.h b/drivers/gpu/drm/i915/intel_bios.h index 4c18514..e1a598f 100644 --- a/drivers/gpu/drm/i915/intel_bios.h +++ b/drivers/gpu/drm/i915/intel_bios.h @@ -197,7 +197,8 @@ struct bdb_general_features { struct child_device_config { u16 handle; u16 device_type; - u8 device_id[10]; /* See DEVICE_TYPE_* above */ + u8 i2c_speed; + u8 rsvd[9]; u16 addin_offset; u8 dvo_port; /* See Device_PORT_* above */ u8 i2c_pin; diff --git a/drivers/gpu/drm/i915/intel_i2c.c b/drivers/gpu/drm/i915/intel_i2c.c index 6f4d1289..9192024 100644 --- a/drivers/gpu/drm/i915/intel_i2c.c +++ b/drivers/gpu/drm/i915/intel_i2c.c @@ -38,6 +38,12 @@ #define I2C_RISEFALL_TIME 20 +static inline struct intel_gmbus * +to_intel_gmbus(struct i2c_adapter *i2c) +{ + return container_of(i2c, struct intel_gmbus, adapter); +} + struct intel_gpio { struct i2c_adapter adapter; struct i2c_algo_bit_data algo; @@ -71,10 +77,27 @@ static void intel_i2c_quirk_set(struct drm_i915_private *dev_priv, bool enable) I915_WRITE(DSPCLK_GATE_D, val); } +static u32 get_reserved(struct intel_gpio *gpio) +{ + struct drm_i915_private *dev_priv = gpio->dev_priv; + struct drm_device *dev = dev_priv->dev; + u32 reserved = 0; + + /* On most chips, these bits must be preserved in software. */ + if (!IS_I830(dev) && !IS_845G(dev)) + reserved = I915_READ(gpio->reg) & (GPIO_DATA_PULLUP_DISABLE | + GPIO_CLOCK_PULLUP_DISABLE); + + return reserved; +} + static int get_clock(void *data) { struct intel_gpio *gpio = data; struct drm_i915_private *dev_priv = gpio->dev_priv; + u32 reserved = get_reserved(gpio); + I915_WRITE(gpio->reg, reserved | GPIO_CLOCK_DIR_MASK); + I915_WRITE(gpio->reg, reserved); return (I915_READ(gpio->reg) & GPIO_CLOCK_VAL_IN) != 0; } @@ -82,6 +105,9 @@ static int get_data(void *data) { struct intel_gpio *gpio = data; struct drm_i915_private *dev_priv = gpio->dev_priv; + u32 reserved = get_reserved(gpio); + I915_WRITE(gpio->reg, reserved | GPIO_DATA_DIR_MASK); + I915_WRITE(gpio->reg, reserved); return (I915_READ(gpio->reg) & GPIO_DATA_VAL_IN) != 0; } @@ -89,13 +115,8 @@ static void set_clock(void *data, int state_high) { struct intel_gpio *gpio = data; struct drm_i915_private *dev_priv = gpio->dev_priv; - struct drm_device *dev = dev_priv->dev; - u32 reserved = 0, clock_bits; - - /* On most chips, these bits must be preserved in software. */ - if (!IS_I830(dev) && !IS_845G(dev)) - reserved = I915_READ(gpio->reg) & (GPIO_DATA_PULLUP_DISABLE | - GPIO_CLOCK_PULLUP_DISABLE); + u32 reserved = get_reserved(gpio); + u32 clock_bits; if (state_high) clock_bits = GPIO_CLOCK_DIR_IN | GPIO_CLOCK_DIR_MASK; @@ -111,13 +132,8 @@ static void set_data(void *data, int state_high) { struct intel_gpio *gpio = data; struct drm_i915_private *dev_priv = gpio->dev_priv; - struct drm_device *dev = dev_priv->dev; - u32 reserved = 0, data_bits; - - /* On most chips, these bits must be preserved in software. */ - if (!IS_I830(dev) && !IS_845G(dev)) - reserved = I915_READ(gpio->reg) & (GPIO_DATA_PULLUP_DISABLE | - GPIO_CLOCK_PULLUP_DISABLE); + u32 reserved = get_reserved(gpio); + u32 data_bits; if (state_high) data_bits = GPIO_DATA_DIR_IN | GPIO_DATA_DIR_MASK; @@ -155,7 +171,7 @@ intel_gpio_create(struct drm_i915_private *dev_priv, u32 pin) gpio->reg += PCH_GPIOA - GPIOA; gpio->dev_priv = dev_priv; - snprintf(gpio->adapter.name, I2C_NAME_SIZE, "GPIO %d", pin); + snprintf(gpio->adapter.name, I2C_NAME_SIZE, "GPIO%c", "?BACDEF?"[pin]); gpio->adapter.owner = THIS_MODULE; gpio->adapter.algo_data = &gpio->algo; gpio->adapter.dev.parent = &dev_priv->dev->pdev->dev; @@ -170,16 +186,6 @@ intel_gpio_create(struct drm_i915_private *dev_priv, u32 pin) if (i2c_bit_add_bus(&gpio->adapter)) goto out_free; - intel_i2c_reset(dev_priv->dev); - - /* JJJ: raise SCL and SDA? */ - intel_i2c_quirk_set(dev_priv, true); - set_data(gpio, 1); - udelay(I2C_RISEFALL_TIME); - set_clock(gpio, 1); - udelay(I2C_RISEFALL_TIME); - intel_i2c_quirk_set(dev_priv, false); - return &gpio->adapter; out_free: @@ -188,17 +194,27 @@ out_free: } static int -quirk_i2c_transfer(struct drm_i915_private *dev_priv, - struct i2c_adapter *adapter, - struct i2c_msg *msgs, - int num) +intel_i2c_quirk_xfer(struct drm_i915_private *dev_priv, + struct i2c_adapter *adapter, + struct i2c_msg *msgs, + int num) { + struct intel_gpio *gpio = container_of(adapter, + struct intel_gpio, + adapter); int ret; intel_i2c_reset(dev_priv->dev); intel_i2c_quirk_set(dev_priv, true); - ret = i2c_transfer(adapter, msgs, num); + set_data(gpio, 1); + set_clock(gpio, 1); + udelay(I2C_RISEFALL_TIME); + + ret = adapter->algo->master_xfer(adapter, msgs, num); + + set_data(gpio, 1); + set_clock(gpio, 1); intel_i2c_quirk_set(dev_priv, false); return ret; @@ -213,21 +229,15 @@ gmbus_xfer(struct i2c_adapter *adapter, struct intel_gmbus, adapter); struct drm_i915_private *dev_priv = adapter->algo_data; - int i, speed, reg_offset; + int i, reg_offset; - if (bus->force_bitbanging) - return quirk_i2c_transfer(dev_priv, bus->force_bitbanging, msgs, num); + if (bus->force_bit) + return intel_i2c_quirk_xfer(dev_priv, + bus->force_bit, msgs, num); reg_offset = HAS_PCH_SPLIT(dev_priv->dev) ? PCH_GMBUS0 - GMBUS0 : 0; - speed = GMBUS_RATE_100KHZ; - if (INTEL_INFO(dev_priv->dev)->gen > 4 || IS_G4X(dev_priv->dev)) { - if (bus->pin == GMBUS_PORT_DPB) /* SDVO only? */ - speed = GMBUS_RATE_1MHZ; - else - speed = GMBUS_RATE_400KHZ; - } - I915_WRITE(GMBUS0 + reg_offset, speed | bus->pin); + I915_WRITE(GMBUS0 + reg_offset, bus->reg0); for (i = 0; i < num; i++) { u16 len = msgs[i].len; @@ -239,6 +249,7 @@ gmbus_xfer(struct i2c_adapter *adapter, (len << GMBUS_BYTE_COUNT_SHIFT) | (msgs[i].addr << GMBUS_SLAVE_ADDR_SHIFT) | GMBUS_SLAVE_READ | GMBUS_SW_RDY); + POSTING_READ(GMBUS2+reg_offset); do { u32 val, loop = 0; @@ -254,20 +265,35 @@ gmbus_xfer(struct i2c_adapter *adapter, } while (--len && ++loop < 4); } while (len); } else { - u32 val = 0, loop = 0; - - BUG_ON(msgs[i].len > 4); + u32 val, loop; + val = loop = 0; do { - val |= *buf++ << (loop*8); - } while (--len && +loop < 4); + val |= *buf++ << (8 * loop); + } while (--len && ++loop < 4); I915_WRITE(GMBUS3 + reg_offset, val); I915_WRITE(GMBUS1 + reg_offset, - (i + 1 == num ? GMBUS_CYCLE_STOP : GMBUS_CYCLE_WAIT ) | + (i + 1 == num ? GMBUS_CYCLE_STOP : GMBUS_CYCLE_WAIT) | (msgs[i].len << GMBUS_BYTE_COUNT_SHIFT) | (msgs[i].addr << GMBUS_SLAVE_ADDR_SHIFT) | GMBUS_SLAVE_WRITE | GMBUS_SW_RDY); + POSTING_READ(GMBUS2+reg_offset); + + while (len) { + if (wait_for(I915_READ(GMBUS2 + reg_offset) & (GMBUS_SATOER | GMBUS_HW_RDY), 50)) + goto timeout; + if (I915_READ(GMBUS2 + reg_offset) & GMBUS_SATOER) + return 0; + + val = loop = 0; + do { + val |= *buf++ << (8 * loop); + } while (--len && ++loop < 4); + + I915_WRITE(GMBUS3 + reg_offset, val); + POSTING_READ(GMBUS2+reg_offset); + } } if (i + 1 < num && wait_for(I915_READ(GMBUS2 + reg_offset) & (GMBUS_SATOER | GMBUS_HW_WAIT_PHASE), 50)) @@ -279,17 +305,25 @@ gmbus_xfer(struct i2c_adapter *adapter, return num; timeout: - DRM_INFO("GMBUS timed out, falling back to bit banging on pin %d\n", bus->pin); + DRM_INFO("GMBUS timed out, falling back to bit banging on pin %d [%s]\n", + bus->reg0 & 0xff, bus->adapter.name); /* Hardware may not support GMBUS over these pins? Try GPIO bitbanging instead. */ - bus->force_bitbanging = intel_gpio_create(dev_priv, bus->pin); - if (!bus->force_bitbanging) + bus->force_bit = intel_gpio_create(dev_priv, bus->reg0 & 0xff); + if (!bus->force_bit) return -ENOMEM; - return quirk_i2c_transfer(dev_priv, bus->force_bitbanging, msgs, num); + return intel_i2c_quirk_xfer(dev_priv, bus->force_bit, msgs, num); } static u32 gmbus_func(struct i2c_adapter *adapter) { + struct intel_gmbus *bus = container_of(adapter, + struct intel_gmbus, + adapter); + + if (bus->force_bit) + bus->force_bit->algo->functionality(bus->force_bit); + return (I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL | /* I2C_FUNC_10BIT_ADDR | */ I2C_FUNC_SMBUS_READ_BLOCK_DATA | @@ -307,15 +341,15 @@ static const struct i2c_algorithm gmbus_algorithm = { */ int intel_setup_gmbus(struct drm_device *dev) { - static const char *names[] = { + static const char *names[GMBUS_NUM_PORTS] = { "disabled", "ssc", "vga", "panel", "dpc", "dpb", - "dpd", "reserved" + "dpd", }; struct drm_i915_private *dev_priv = dev->dev_private; int ret, i; @@ -343,7 +377,8 @@ int intel_setup_gmbus(struct drm_device *dev) if (ret) goto err; - bus->pin = i; + /* By default use a conservative clock rate */ + bus->reg0 = i | GMBUS_RATE_100KHZ; } intel_i2c_reset(dev_priv->dev); @@ -360,6 +395,38 @@ err: return ret; } +void intel_gmbus_set_speed(struct i2c_adapter *adapter, int speed) +{ + struct intel_gmbus *bus = to_intel_gmbus(adapter); + + /* speed: + * 0x0 = 100 KHz + * 0x1 = 50 KHz + * 0x2 = 400 KHz + * 0x3 = 1000 Khz + */ + bus->reg0 = (bus->reg0 & ~(0x3 << 8)) | (speed << 8); +} + +void intel_gmbus_force_bit(struct i2c_adapter *adapter, bool force_bit) +{ + struct intel_gmbus *bus = to_intel_gmbus(adapter); + + if (force_bit) { + if (bus->force_bit == NULL) { + struct drm_i915_private *dev_priv = adapter->algo_data; + bus->force_bit = intel_gpio_create(dev_priv, + bus->reg0 & 0xff); + } + } else { + if (bus->force_bit) { + i2c_del_adapter(bus->force_bit); + kfree(bus->force_bit); + bus->force_bit = NULL; + } + } +} + void intel_teardown_gmbus(struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; @@ -370,9 +437,9 @@ void intel_teardown_gmbus(struct drm_device *dev) for (i = 0; i < GMBUS_NUM_PORTS; i++) { struct intel_gmbus *bus = &dev_priv->gmbus[i]; - if (bus->force_bitbanging) { - i2c_del_adapter(bus->force_bitbanging); - kfree(bus->force_bitbanging); + if (bus->force_bit) { + i2c_del_adapter(bus->force_bit); + kfree(bus->force_bit); } i2c_del_adapter(&bus->adapter); } diff --git a/drivers/gpu/drm/i915/intel_sdvo.c b/drivers/gpu/drm/i915/intel_sdvo.c index 7cd2d95..b684a40 100644 --- a/drivers/gpu/drm/i915/intel_sdvo.c +++ b/drivers/gpu/drm/i915/intel_sdvo.c @@ -68,6 +68,8 @@ struct intel_sdvo { struct i2c_adapter *i2c; u8 slave_addr; + struct i2c_adapter ddc; + /* Register for the SDVO device: SDVOB or SDVOC */ int sdvo_reg; @@ -247,49 +249,29 @@ static void intel_sdvo_write_sdvox(struct intel_sdvo *intel_sdvo, u32 val) static bool intel_sdvo_read_byte(struct intel_sdvo *intel_sdvo, u8 addr, u8 *ch) { - u8 out_buf[2] = { addr, 0 }; - u8 buf[2]; struct i2c_msg msgs[] = { { - .addr = intel_sdvo->slave_addr >> 1, + .addr = intel_sdvo->slave_addr, .flags = 0, .len = 1, - .buf = out_buf, + .buf = &addr, }, { - .addr = intel_sdvo->slave_addr >> 1, + .addr = intel_sdvo->slave_addr, .flags = I2C_M_RD, .len = 1, - .buf = buf, + .buf = ch, } }; int ret; if ((ret = i2c_transfer(intel_sdvo->i2c, msgs, 2)) == 2) - { - *ch = buf[0]; return true; - } DRM_DEBUG_KMS("i2c transfer returned %d\n", ret); return false; } -static bool intel_sdvo_write_byte(struct intel_sdvo *intel_sdvo, int addr, u8 ch) -{ - u8 out_buf[2] = { addr, ch }; - struct i2c_msg msgs[] = { - { - .addr = intel_sdvo->slave_addr >> 1, - .flags = 0, - .len = 2, - .buf = out_buf, - } - }; - - return i2c_transfer(intel_sdvo->i2c, msgs, 1) == 1; -} - #define SDVO_CMD_NAME_ENTRY(cmd) {cmd, #cmd} /** Mapping of command numbers to names, for debug output */ static const struct _sdvo_cmd_name { @@ -434,32 +416,80 @@ static void intel_sdvo_debug_write(struct intel_sdvo *intel_sdvo, u8 cmd, DRM_LOG_KMS("\n"); } +static const char *cmd_status_names[] = { + "Power on", + "Success", + "Not supported", + "Invalid arg", + "Pending", + "Target not specified", + "Scaling not supported" +}; + static bool intel_sdvo_write_cmd(struct intel_sdvo *intel_sdvo, u8 cmd, const void *args, int args_len) { - int i; + u8 buf[args_len*2 + 2], status; + struct i2c_msg msgs[args_len + 3]; + int i, ret; intel_sdvo_debug_write(intel_sdvo, cmd, args, args_len); for (i = 0; i < args_len; i++) { - if (!intel_sdvo_write_byte(intel_sdvo, SDVO_I2C_ARG_0 - i, - ((u8*)args)[i])) + msgs[i].addr = intel_sdvo->slave_addr; + msgs[i].flags = 0; + msgs[i].len = 2; + msgs[i].buf = buf + 2 *i; + buf[2*i + 0] = SDVO_I2C_ARG_0 - i; + buf[2*i + 1] = ((u8*)args)[i]; + } + msgs[i].addr = intel_sdvo->slave_addr; + msgs[i].flags = 0; + msgs[i].len = 2; + msgs[i].buf = buf + 2*i; + buf[2*i + 0] = SDVO_I2C_OPCODE; + buf[2*i + 1] = cmd; + + /* the following two are to read the response */ + status = SDVO_I2C_CMD_STATUS; + msgs[i+1].addr = intel_sdvo->slave_addr; + msgs[i+1].flags = 0; + msgs[i+1].len = 1; + msgs[i+1].buf = &status; + + msgs[i+2].addr = intel_sdvo->slave_addr; + msgs[i+2].flags = I2C_M_RD; + msgs[i+2].len = 1; + msgs[i+2].buf = &status; + + ret = i2c_transfer(intel_sdvo->i2c, msgs, i+3); + if (ret < 0) { + DRM_DEBUG_KMS("I2c transfer returned %d\n", ret); + return false; + } + if (ret != i+3) { + /* failure in I2C transfer */ + DRM_DEBUG_KMS("I2c transfer returned %d/%d\n", ret, i+3); + return false; + } + + i = 3; + while (status == SDVO_CMD_STATUS_PENDING && i--) { + if (!intel_sdvo_read_byte(intel_sdvo, + SDVO_I2C_CMD_STATUS, + &status)) return false; } + if (status != SDVO_CMD_STATUS_SUCCESS) { + DRM_DEBUG_KMS("command returns response %s [%d]\n", + status <= SDVO_CMD_STATUS_SCALING_NOT_SUPP ? cmd_status_names[status] : "???", + status); + return false; + } - return intel_sdvo_write_byte(intel_sdvo, SDVO_I2C_OPCODE, cmd); + return true; } -static const char *cmd_status_names[] = { - "Power on", - "Success", - "Not supported", - "Invalid arg", - "Pending", - "Target not specified", - "Scaling not supported" -}; - static bool intel_sdvo_read_response(struct intel_sdvo *intel_sdvo, void *response, int response_len) { @@ -497,13 +527,9 @@ static bool intel_sdvo_read_response(struct intel_sdvo *intel_sdvo, SDVO_I2C_RETURN_0 + i, &((u8 *)response)[i])) goto log_fail; - DRM_LOG_KMS("%02X ", ((u8 *)response)[i]); + DRM_LOG_KMS(" %02X", ((u8 *)response)[i]); } - - for (; i < 8; i++) - DRM_LOG_KMS(" "); DRM_LOG_KMS("\n"); - return true; log_fail: @@ -521,75 +547,17 @@ static int intel_sdvo_get_pixel_multiplier(struct drm_display_mode *mode) return 4; } -/** - * Try to read the response after issuie the DDC switch command. But it - * is noted that we must do the action of reading response and issuing DDC - * switch command in one I2C transaction. Otherwise when we try to start - * another I2C transaction after issuing the DDC bus switch, it will be - * switched to the internal SDVO register. - */ -static int intel_sdvo_set_control_bus_switch(struct intel_sdvo *intel_sdvo, - u8 target) +static bool intel_sdvo_set_control_bus_switch(struct intel_sdvo *intel_sdvo, + u8 ddc_bus) { - u8 out_buf[2], cmd_buf[2], ret_value[2], ret; - struct i2c_msg msgs[] = { - { - .addr = intel_sdvo->slave_addr >> 1, - .flags = 0, - .len = 2, - .buf = out_buf, - }, - /* the following two are to read the response */ - { - .addr = intel_sdvo->slave_addr >> 1, - .flags = 0, - .len = 1, - .buf = cmd_buf, - }, - { - .addr = intel_sdvo->slave_addr >> 1, - .flags = I2C_M_RD, - .len = 1, - .buf = ret_value, - }, - }; - - intel_sdvo_debug_write(intel_sdvo, SDVO_CMD_SET_CONTROL_BUS_SWITCH, - &target, 1); - /* write the DDC switch command argument */ - if (!intel_sdvo_write_byte(intel_sdvo, SDVO_I2C_ARG_0, target)) - return -EIO; - - out_buf[0] = SDVO_I2C_OPCODE; - out_buf[1] = SDVO_CMD_SET_CONTROL_BUS_SWITCH; - cmd_buf[0] = SDVO_I2C_CMD_STATUS; - cmd_buf[1] = 0; - ret_value[0] = 0; - ret_value[1] = 0; - - ret = i2c_transfer(intel_sdvo->i2c, msgs, 3); - if (ret < 0) - return ret; - if (ret != 3) { - /* failure in I2C transfer */ - DRM_DEBUG_KMS("I2c transfer returned %d\n", ret); - return -EIO; - } - if (ret_value[0] != SDVO_CMD_STATUS_SUCCESS) { - DRM_DEBUG_KMS("DDC switch command returns response %d\n", - ret_value[0]); - return -EIO; - } - - return 0; + return intel_sdvo_write_cmd(intel_sdvo, + SDVO_CMD_SET_CONTROL_BUS_SWITCH, + &ddc_bus, 1); } static bool intel_sdvo_set_value(struct intel_sdvo *intel_sdvo, u8 cmd, const void *data, int len) { - if (!intel_sdvo_write_cmd(intel_sdvo, cmd, data, len)) - return false; - - return intel_sdvo_read_response(intel_sdvo, NULL, 0); + return intel_sdvo_write_cmd(intel_sdvo, cmd, data, len); } static bool @@ -1272,7 +1240,38 @@ static int intel_sdvo_mode_valid(struct drm_connector *connector, static bool intel_sdvo_get_capabilities(struct intel_sdvo *intel_sdvo, struct intel_sdvo_caps *caps) { - return intel_sdvo_get_value(intel_sdvo, SDVO_CMD_GET_DEVICE_CAPS, caps, sizeof(*caps)); + if (!intel_sdvo_get_value(intel_sdvo, + SDVO_CMD_GET_DEVICE_CAPS, + caps, sizeof(*caps))) + return false; + + DRM_DEBUG_KMS("SDVO capabilities:\n" + " vendor_id: %d\n" + " device_id: %d\n" + " device_rev_id: %d\n" + " sdvo_version_major: %d\n" + " sdvo_version_minor: %d\n" + " sdvo_inputs_mask: %d\n" + " smooth_scaling: %d\n" + " sharp_scaling: %d\n" + " up_scaling: %d\n" + " down_scaling: %d\n" + " stall_support: %d\n" + " output_flags: %d\n", + caps->vendor_id, + caps->device_id, + caps->device_rev_id, + caps->sdvo_version_major, + caps->sdvo_version_minor, + caps->sdvo_inputs_mask, + caps->smooth_scaling, + caps->sharp_scaling, + caps->up_scaling, + caps->down_scaling, + caps->stall_support, + caps->output_flags); + + return true; } /* No use! */ @@ -1377,16 +1376,10 @@ intel_sdvo_multifunc_encoder(struct intel_sdvo *intel_sdvo) } static struct edid * -intel_sdvo_get_edid(struct drm_connector *connector, int ddc) +intel_sdvo_get_edid(struct drm_connector *connector) { - struct intel_sdvo *intel_sdvo = intel_attached_sdvo(connector); - int ret; - - ret = intel_sdvo_set_control_bus_switch(intel_sdvo, ddc); - if (ret) - return NULL; - - return drm_get_edid(connector, intel_sdvo->i2c); + struct intel_sdvo *sdvo = intel_attached_sdvo(connector); + return drm_get_edid(connector, &sdvo->ddc); } static struct drm_connector * @@ -1447,26 +1440,27 @@ intel_sdvo_hdmi_sink_detect(struct drm_connector *connector) enum drm_connector_status status; struct edid *edid; - edid = intel_sdvo_get_edid(connector, intel_sdvo->ddc_bus); + edid = intel_sdvo_get_edid(connector); if (edid == NULL && intel_sdvo_multifunc_encoder(intel_sdvo)) { - u8 ddc; + u8 ddc, saved_ddc = intel_sdvo->ddc_bus; /* * Don't use the 1 as the argument of DDC bus switch to get * the EDID. It is used for SDVO SPD ROM. */ for (ddc = intel_sdvo->ddc_bus >> 1; ddc > 1; ddc >>= 1) { - edid = intel_sdvo_get_edid(connector, ddc); - if (edid) { - /* - * If we found the EDID on the other bus, - * assume that is the correct DDC bus. - */ - intel_sdvo->ddc_bus = ddc; + intel_sdvo->ddc_bus = ddc; + edid = intel_sdvo_get_edid(connector); + if (edid) break; - } } + /* + * If we found the EDID on the other bus, + * assume that is the correct DDC bus. + */ + if (edid == NULL) + intel_sdvo->ddc_bus = saved_ddc; } /* @@ -1499,7 +1493,7 @@ intel_sdvo_detect(struct drm_connector *connector, bool force) enum drm_connector_status ret; if (!intel_sdvo_write_cmd(intel_sdvo, - SDVO_CMD_GET_ATTACHED_DISPLAYS, NULL, 0)) + SDVO_CMD_GET_ATTACHED_DISPLAYS, NULL, 0)) return connector_status_unknown; if (intel_sdvo->is_tv) { /* add 30ms delay when the output type is SDVO-TV */ @@ -1508,7 +1502,9 @@ intel_sdvo_detect(struct drm_connector *connector, bool force) if (!intel_sdvo_read_response(intel_sdvo, &response, 2)) return connector_status_unknown; - DRM_DEBUG_KMS("SDVO response %d %d\n", response & 0xff, response >> 8); + DRM_DEBUG_KMS("SDVO response %d %d [%x]\n", + response & 0xff, response >> 8, + intel_sdvo_connector->output_flag); if (response == 0) return connector_status_disconnected; @@ -1541,11 +1537,10 @@ intel_sdvo_detect(struct drm_connector *connector, bool force) static void intel_sdvo_get_ddc_modes(struct drm_connector *connector) { - struct intel_sdvo *intel_sdvo = intel_attached_sdvo(connector); struct edid *edid; /* set the bus switch and get the modes */ - edid = intel_sdvo_get_edid(connector, intel_sdvo->ddc_bus); + edid = intel_sdvo_get_edid(connector); /* * Mac mini hack. On this device, the DVI-I connector shares one DDC @@ -1647,7 +1642,8 @@ static void intel_sdvo_get_tv_modes(struct drm_connector *connector) return; BUILD_BUG_ON(sizeof(tv_res) != 3); - if (!intel_sdvo_write_cmd(intel_sdvo, SDVO_CMD_GET_SDTV_RESOLUTION_SUPPORT, + if (!intel_sdvo_write_cmd(intel_sdvo, + SDVO_CMD_GET_SDTV_RESOLUTION_SUPPORT, &tv_res, sizeof(tv_res))) return; if (!intel_sdvo_read_response(intel_sdvo, &reply, 3)) @@ -1924,6 +1920,7 @@ static void intel_sdvo_enc_destroy(struct drm_encoder *encoder) drm_mode_destroy(encoder->dev, intel_sdvo->sdvo_lvds_fixed_mode); + i2c_del_adapter(&intel_sdvo->ddc); intel_encoder_destroy(encoder); } @@ -1991,6 +1988,30 @@ intel_sdvo_select_ddc_bus(struct drm_i915_private *dev_priv, intel_sdvo_guess_ddc_bus(sdvo); } +static void +intel_sdvo_select_i2c_bus(struct drm_i915_private *dev_priv, + struct intel_sdvo *sdvo, u32 reg) +{ + struct sdvo_device_mapping *mapping; + u8 pin, speed; + + if (IS_SDVOB(reg)) + mapping = &dev_priv->sdvo_mappings[0]; + else + mapping = &dev_priv->sdvo_mappings[1]; + + pin = GMBUS_PORT_DPB; + speed = GMBUS_RATE_1MHZ >> 8; + if (mapping->initialized) { + pin = mapping->i2c_pin; + speed = mapping->i2c_speed; + } + + sdvo->i2c = &dev_priv->gmbus[pin].adapter; + intel_gmbus_set_speed(sdvo->i2c, speed); + intel_gmbus_force_bit(sdvo->i2c, true); +} + static bool intel_sdvo_get_digital_encoding_mode(struct intel_sdvo *intel_sdvo, int device) { @@ -2504,7 +2525,43 @@ static bool intel_sdvo_create_enhance_property(struct intel_sdvo *intel_sdvo, return intel_sdvo_create_enhance_property_lvds(intel_sdvo, intel_sdvo_connector, enhancements.reply); else return true; +} + +static int intel_sdvo_ddc_proxy_xfer(struct i2c_adapter *adapter, + struct i2c_msg *msgs, + int num) +{ + struct intel_sdvo *sdvo = adapter->algo_data; + if (!intel_sdvo_set_control_bus_switch(sdvo, sdvo->ddc_bus)) + return -EIO; + + return sdvo->i2c->algo->master_xfer(sdvo->i2c, msgs, num); +} + +static u32 intel_sdvo_ddc_proxy_func(struct i2c_adapter *adapter) +{ + struct intel_sdvo *sdvo = adapter->algo_data; + return sdvo->i2c->algo->functionality(sdvo->i2c); +} + +static const struct i2c_algorithm intel_sdvo_ddc_proxy = { + .master_xfer = intel_sdvo_ddc_proxy_xfer, + .functionality = intel_sdvo_ddc_proxy_func +}; + +static bool +intel_sdvo_init_ddc_proxy(struct intel_sdvo *sdvo, + struct drm_device *dev) +{ + sdvo->ddc.owner = THIS_MODULE; + sdvo->ddc.class = I2C_CLASS_DDC; + snprintf(sdvo->ddc.name, I2C_NAME_SIZE, "SDVO DDC proxy"); + sdvo->ddc.dev.parent = &dev->pdev->dev; + sdvo->ddc.algo_data = sdvo; + sdvo->ddc.algo = &intel_sdvo_ddc_proxy; + + return i2c_add_adapter(&sdvo->ddc) == 0; } bool intel_sdvo_init(struct drm_device *dev, int sdvo_reg) @@ -2518,6 +2575,11 @@ bool intel_sdvo_init(struct drm_device *dev, int sdvo_reg) if (!intel_sdvo) return false; + if (!intel_sdvo_init_ddc_proxy(intel_sdvo, dev)) { + kfree(intel_sdvo); + return false; + } + intel_sdvo->sdvo_reg = sdvo_reg; intel_encoder = &intel_sdvo->base; @@ -2525,9 +2587,8 @@ bool intel_sdvo_init(struct drm_device *dev, int sdvo_reg) /* encoder type will be decided later */ drm_encoder_init(dev, &intel_encoder->base, &intel_sdvo_enc_funcs, 0); - intel_sdvo->i2c = &dev_priv->gmbus[GMBUS_PORT_DPB].adapter; - - intel_sdvo->slave_addr = intel_sdvo_get_slave_addr(dev, sdvo_reg); + intel_sdvo->slave_addr = intel_sdvo_get_slave_addr(dev, sdvo_reg) >> 1; + intel_sdvo_select_i2c_bus(dev_priv, intel_sdvo, sdvo_reg); /* Read the regs to test if we can talk to the device */ for (i = 0; i < 0x40; i++) { @@ -2589,6 +2650,7 @@ bool intel_sdvo_init(struct drm_device *dev, int sdvo_reg) err: drm_encoder_cleanup(&intel_encoder->base); + i2c_del_adapter(&intel_sdvo->ddc); kfree(intel_sdvo); return false; -- cgit v1.1 From cb8ea7527b813dd6e19fb07328f7867a5f0a8d0a Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Tue, 28 Sep 2010 13:35:47 +0100 Subject: drm/i915: Use i2c bit banging instead of GMBUS There are several reported instances of GMBUS failing to successfully read the EDID, so revert back to bit banging until the issue is resolved. Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=30371 Signed-off-by: Chris Wilson --- drivers/gpu/drm/i915/intel_i2c.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/gpu/drm/i915/intel_i2c.c b/drivers/gpu/drm/i915/intel_i2c.c index 9192024..2449a74 100644 --- a/drivers/gpu/drm/i915/intel_i2c.c +++ b/drivers/gpu/drm/i915/intel_i2c.c @@ -379,6 +379,9 @@ int intel_setup_gmbus(struct drm_device *dev) /* By default use a conservative clock rate */ bus->reg0 = i | GMBUS_RATE_100KHZ; + + /* XXX force bit banging until GMBUS is fully debugged */ + bus->force_bit = intel_gpio_create(dev_priv, i); } intel_i2c_reset(dev_priv->dev); -- cgit v1.1 From 8daf7473203cd9bd1b9b98200ee1c74dfe4826fe Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Tue, 28 Sep 2010 14:07:26 +0100 Subject: MAINTAINERS: Add contact details for drm/i915 Signed-off-by: Chris Wilson --- MAINTAINERS | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/MAINTAINERS b/MAINTAINERS index 50b8148..5190fb9 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -2051,6 +2051,15 @@ S: Maintained F: drivers/gpu/drm/ F: include/drm/ +INTEL DRM DRIVERS (excluding Poulsbo, Moorestown and derivative chipsets) +M: Chris Wilson +L: intel-gfx@lists.freedesktop.org +L: dri-devel@lists.freedesktop.org +T: git git://git.kernel.org/pub/scm/linux/kernel/git/ickle/drm-intel.git +S: Supported +F: drivers/gpu/drm/i915 +F: include/drm/i915* + DSCC4 DRIVER M: Francois Romieu L: netdev@vger.kernel.org -- cgit v1.1 From b8232e906381dcba2bb26f0d849d4c25cc9b1368 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Tue, 28 Sep 2010 16:41:32 +0100 Subject: drm/i915: Disable LVDS i2c probing when using GPIO bit banging This check only appears to succeed when using GMBUS, so we need to skip it if we have fallen back to using GPIO bit banging. Signed-off-by: Chris Wilson --- drivers/gpu/drm/i915/i915_drv.h | 4 ++++ drivers/gpu/drm/i915/intel_lvds.c | 3 +++ 2 files changed, 7 insertions(+) diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 0bb2553..0ce76a8 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -1108,6 +1108,10 @@ extern int intel_setup_gmbus(struct drm_device *dev); extern void intel_teardown_gmbus(struct drm_device *dev); extern void intel_gmbus_set_speed(struct i2c_adapter *adapter, int speed); extern void intel_gmbus_force_bit(struct i2c_adapter *adapter, bool force_bit); +extern inline bool intel_gmbus_is_forced_bit(struct i2c_adapter *adapter) +{ + return container_of(adapter, struct intel_gmbus, adapter)->force_bit; +} extern void intel_i2c_reset(struct drm_device *dev); /* intel_opregion.c */ diff --git a/drivers/gpu/drm/i915/intel_lvds.c b/drivers/gpu/drm/i915/intel_lvds.c index 98172bc..f1a6499 100644 --- a/drivers/gpu/drm/i915/intel_lvds.c +++ b/drivers/gpu/drm/i915/intel_lvds.c @@ -827,6 +827,9 @@ static bool intel_lvds_ddc_probe(struct drm_device *dev, u8 pin) }, }; struct i2c_adapter *i2c = &dev_priv->gmbus[pin].adapter; + /* XXX this only appears to work when using GMBUS */ + if (intel_gmbus_is_forced_bit(i2c)) + return true; return i2c_transfer(i2c, msgs, 1) == 1; } -- cgit v1.1 From a8ed0b16a924a59b56906e83d6c033a04a9818f6 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Tue, 28 Sep 2010 23:33:17 +0100 Subject: drm/i915: Tidy dvo_ch7017 and print out which chip we detect Signed-off-by: Chris Wilson --- drivers/gpu/drm/i915/dvo_ch7017.c | 63 +++++++++++++++++---------------------- 1 file changed, 27 insertions(+), 36 deletions(-) diff --git a/drivers/gpu/drm/i915/dvo_ch7017.c b/drivers/gpu/drm/i915/dvo_ch7017.c index 0bc8ce1..af70337 100644 --- a/drivers/gpu/drm/i915/dvo_ch7017.c +++ b/drivers/gpu/drm/i915/dvo_ch7017.c @@ -165,56 +165,35 @@ struct ch7017_priv { static void ch7017_dump_regs(struct intel_dvo_device *dvo); static void ch7017_dpms(struct intel_dvo_device *dvo, int mode); -static bool ch7017_read(struct intel_dvo_device *dvo, int addr, uint8_t *val) +static bool ch7017_read(struct intel_dvo_device *dvo, u8 addr, u8 *val) { - struct i2c_adapter *adapter = dvo->i2c_bus; - u8 out_buf[2]; - u8 in_buf[2]; - struct i2c_msg msgs[] = { { .addr = dvo->slave_addr, .flags = 0, .len = 1, - .buf = out_buf, + .buf = &addr, }, { .addr = dvo->slave_addr, .flags = I2C_M_RD, .len = 1, - .buf = in_buf, + .buf = val, } }; - - out_buf[0] = addr; - out_buf[1] = 0; - - if (i2c_transfer(adapter, msgs, 2) == 2) { - *val= in_buf[0]; - return true; - }; - - return false; + return i2c_transfer(dvo->i2c_bus, msgs, 2) == 2; } -static bool ch7017_write(struct intel_dvo_device *dvo, int addr, uint8_t val) +static bool ch7017_write(struct intel_dvo_device *dvo, u8 addr, u8 val) { - struct i2c_adapter *adapter = dvo->i2c_bus; - uint8_t out_buf[2]; + uint8_t buf[2] = { addr, val }; struct i2c_msg msg = { .addr = dvo->slave_addr, .flags = 0, .len = 2, - .buf = out_buf, + .buf = buf, }; - - out_buf[0] = addr; - out_buf[1] = val; - - if (i2c_transfer(adapter, &msg, 1) == 1) - return true; - - return false; + return i2c_transfer(dvo->i2c_bus, &msg, 1) == 1; } /** Probes for a CH7017 on the given bus and slave address. */ @@ -222,7 +201,8 @@ static bool ch7017_init(struct intel_dvo_device *dvo, struct i2c_adapter *adapter) { struct ch7017_priv *priv; - uint8_t val; + const char *str; + u8 val; priv = kzalloc(sizeof(struct ch7017_priv), GFP_KERNEL); if (priv == NULL) @@ -234,16 +214,27 @@ static bool ch7017_init(struct intel_dvo_device *dvo, if (!ch7017_read(dvo, CH7017_DEVICE_ID, &val)) goto fail; - if (val != CH7017_DEVICE_ID_VALUE && - val != CH7018_DEVICE_ID_VALUE && - val != CH7019_DEVICE_ID_VALUE) { + switch (val) { + case CH7017_DEVICE_ID_VALUE: + str = "ch7017"; + break; + case CH7018_DEVICE_ID_VALUE: + str = "ch7018"; + break; + case CH7019_DEVICE_ID_VALUE: + str = "ch7019"; + break; + default: DRM_DEBUG_KMS("ch701x not detected, got %d: from %s " - "Slave %d.\n", - val, adapter->name,dvo->slave_addr); + "slave %d.\n", + val, adapter->name,dvo->slave_addr); goto fail; } + DRM_DEBUG_KMS("%s detected on %s, addr %d\n", + str, adapter->name, dvo->slave_addr); return true; + fail: kfree(priv); return false; @@ -365,7 +356,7 @@ static void ch7017_dpms(struct intel_dvo_device *dvo, int mode) } /* XXX: Should actually wait for update power status somehow */ - udelay(20000); + msleep(20); } static void ch7017_dump_regs(struct intel_dvo_device *dvo) -- cgit v1.1 From f573c66061184ce28196a22229b6214256ceacd8 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Tue, 28 Sep 2010 23:34:44 +0100 Subject: drm/i915/dvo: Fix panel and DDC i2c pins Signed-off-by: Chris Wilson --- drivers/gpu/drm/i915/intel_dvo.c | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_dvo.c b/drivers/gpu/drm/i915/intel_dvo.c index 561fbc3..ea37328 100644 --- a/drivers/gpu/drm/i915/intel_dvo.c +++ b/drivers/gpu/drm/i915/intel_dvo.c @@ -81,7 +81,6 @@ struct intel_dvo { struct intel_encoder base; struct intel_dvo_device dev; - int ddc_bus; struct drm_display_mode *panel_fixed_mode; bool panel_wants_dither; @@ -245,7 +244,7 @@ static int intel_dvo_get_modes(struct drm_connector *connector) * that's not the case. */ intel_ddc_get_modes(connector, - &dev_priv->gmbus[intel_dvo->ddc_bus].adapter); + &dev_priv->gmbus[GMBUS_PORT_DPC].adapter); if (!list_empty(&connector->probed_modes)) return 1; @@ -349,7 +348,6 @@ void intel_dvo_init(struct drm_device *dev) struct intel_encoder *intel_encoder; struct intel_dvo *intel_dvo; struct intel_connector *intel_connector; - int ret = 0; int i; int encoder_type = DRM_MODE_ENCODER_NONE; @@ -367,9 +365,6 @@ void intel_dvo_init(struct drm_device *dev) drm_encoder_init(dev, &intel_encoder->base, &intel_dvo_enc_funcs, encoder_type); - /* Set up the DDC bus */ - intel_dvo->ddc_bus = GMBUS_PORT_DPB; - /* Now, try to find a controller */ for (i = 0; i < ARRAY_SIZE(intel_dvo_devices); i++) { struct drm_connector *connector = &intel_connector->base; @@ -384,7 +379,7 @@ void intel_dvo_init(struct drm_device *dev) if (dvo->gpio != 0) gpio = dvo->gpio; else if (dvo->type == INTEL_DVO_CHIP_LVDS) - gpio = GMBUS_PORT_PANEL; + gpio = GMBUS_PORT_SSC; else gpio = GMBUS_PORT_DPB; @@ -395,8 +390,7 @@ void intel_dvo_init(struct drm_device *dev) i2c = &dev_priv->gmbus[gpio].adapter; intel_dvo->dev = *dvo; - ret = dvo->dev_ops->init(&intel_dvo->dev, i2c); - if (!ret) + if (!dvo->dev_ops->init(&intel_dvo->dev, i2c)) continue; intel_encoder->type = INTEL_OUTPUT_DVO; -- cgit v1.1 From 97d1ebaf81491afd8b45186056eda7ebf5da7875 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Wed, 29 Sep 2010 11:36:22 +0100 Subject: drm/i915/debug: Remove defunct WATCH_LRU This has bitrotted through inuse and superseded by tracing and debugfs. Signed-off-by: Chris Wilson --- drivers/gpu/drm/i915/i915_drv.h | 2 -- drivers/gpu/drm/i915/i915_gem.c | 16 ---------------- drivers/gpu/drm/i915/i915_gem_debug.c | 35 ----------------------------------- drivers/gpu/drm/i915/i915_gem_evict.c | 3 --- 4 files changed, 56 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 0ce76a8..703b8c9 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -77,7 +77,6 @@ enum plane { #define WATCH_COHERENCY 0 #define WATCH_BUF 0 #define WATCH_EXEC 0 -#define WATCH_LRU 0 #define WATCH_RELOC 0 #define WATCH_INACTIVE 0 #define WATCH_PWRITE 0 @@ -1089,7 +1088,6 @@ void i915_verify_inactive(struct drm_device *dev, char *file, int line); void i915_gem_object_check_coherency(struct drm_gem_object *obj, int handle); void i915_gem_dump_object(struct drm_gem_object *obj, int len, const char *where, uint32_t mark); -void i915_dump_lru(struct drm_device *dev, const char *where); /* i915_debugfs.c */ int i915_debugfs_init(struct drm_minor *minor); diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index 81513fa..5ce14f1 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -1865,12 +1865,6 @@ i915_gem_retire_requests_ring(struct drm_device *dev, break; obj = &obj_priv->base; - -#if WATCH_LRU - DRM_INFO("%s: retire %d moves to inactive list %p\n", - __func__, request->seqno, obj); -#endif - if (obj->write_domain != 0) i915_gem_object_move_to_flushing(obj); else @@ -2646,9 +2640,6 @@ i915_gem_object_bind_to_gtt(struct drm_gem_object *obj, unsigned alignment) /* If the gtt is empty and we're still having trouble * fitting our object in, we're out of memory. */ -#if WATCH_LRU - DRM_INFO("%s: GTT full, evicting something\n", __func__); -#endif ret = i915_gem_evict_something(dev, obj->size, alignment); if (ret) return ret; @@ -3950,18 +3941,11 @@ i915_gem_do_execbuffer(struct drm_device *dev, void *data, obj_priv = to_intel_bo(obj); i915_gem_object_move_to_active(obj, ring); -#if WATCH_LRU - DRM_INFO("%s: move to exec list %p\n", __func__, obj); -#endif } i915_add_request(dev, file_priv, request, ring); request = NULL; -#if WATCH_LRU - i915_dump_lru(dev, __func__); -#endif - i915_verify_inactive(dev, __FILE__, __LINE__); err: diff --git a/drivers/gpu/drm/i915/i915_gem_debug.c b/drivers/gpu/drm/i915/i915_gem_debug.c index 80f380b..26e67ee 100644 --- a/drivers/gpu/drm/i915/i915_gem_debug.c +++ b/drivers/gpu/drm/i915/i915_gem_debug.c @@ -97,41 +97,6 @@ i915_gem_dump_object(struct drm_gem_object *obj, int len, } #endif -#if WATCH_LRU -void -i915_dump_lru(struct drm_device *dev, const char *where) -{ - drm_i915_private_t *dev_priv = dev->dev_private; - struct drm_i915_gem_object *obj_priv; - - DRM_INFO("active list %s {\n", where); - spin_lock(&dev_priv->mm.active_list_lock); - list_for_each_entry(obj_priv, &dev_priv->mm.active_list, - list) - { - DRM_INFO(" %p: %08x\n", obj_priv, - obj_priv->last_rendering_seqno); - } - spin_unlock(&dev_priv->mm.active_list_lock); - DRM_INFO("}\n"); - DRM_INFO("flushing list %s {\n", where); - list_for_each_entry(obj_priv, &dev_priv->mm.flushing_list, - list) - { - DRM_INFO(" %p: %08x\n", obj_priv, - obj_priv->last_rendering_seqno); - } - DRM_INFO("}\n"); - DRM_INFO("inactive %s {\n", where); - list_for_each_entry(obj_priv, &dev_priv->mm.inactive_list, list) { - DRM_INFO(" %p: %08x\n", obj_priv, - obj_priv->last_rendering_seqno); - } - DRM_INFO("}\n"); -} -#endif - - #if WATCH_COHERENCY void i915_gem_object_check_coherency(struct drm_gem_object *obj, int handle) diff --git a/drivers/gpu/drm/i915/i915_gem_evict.c b/drivers/gpu/drm/i915/i915_gem_evict.c index 63ac3d2..c503c81 100644 --- a/drivers/gpu/drm/i915/i915_gem_evict.c +++ b/drivers/gpu/drm/i915/i915_gem_evict.c @@ -190,9 +190,6 @@ found: /* Unbinding will emit any required flushes */ list_for_each_entry_safe(obj_priv, tmp_obj_priv, &eviction_list, evict_list) { -#if WATCH_LRU - DRM_INFO("%s: evicting %p\n", __func__, &obj_priv->base); -#endif ret = i915_gem_object_unbind(&obj_priv->base); if (ret) return ret; -- cgit v1.1 From 3d2a812ae4676b74f2033cf09c855074d06f3872 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Wed, 29 Sep 2010 11:39:53 +0100 Subject: drm/i915/debug: Remove default WATCH_BUF Replaced by tracepoints. Signed-off-by: Chris Wilson --- drivers/gpu/drm/i915/i915_drv.h | 1 - drivers/gpu/drm/i915/i915_gem.c | 53 ++--------------------------------- drivers/gpu/drm/i915/i915_gem_debug.c | 2 +- 3 files changed, 3 insertions(+), 53 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 703b8c9..cb4e9a6 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -75,7 +75,6 @@ enum plane { #define DRIVER_PATCHLEVEL 0 #define WATCH_COHERENCY 0 -#define WATCH_BUF 0 #define WATCH_EXEC 0 #define WATCH_RELOC 0 #define WATCH_INACTIVE 0 diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index 5ce14f1..9a8e675 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -1092,10 +1092,6 @@ i915_gem_set_domain_ioctl(struct drm_device *dev, void *data, intel_mark_busy(dev, obj); -#if WATCH_BUF - DRM_INFO("set_domain_ioctl %p(%zd), %08x %08x\n", - obj, obj->size, read_domains, write_domain); -#endif if (read_domains & I915_GEM_DOMAIN_GTT) { ret = i915_gem_object_set_to_gtt_domain(obj, write_domain != 0); @@ -1137,7 +1133,6 @@ i915_gem_sw_finish_ioctl(struct drm_device *dev, void *data, { struct drm_i915_gem_sw_finish *args = data; struct drm_gem_object *obj; - struct drm_i915_gem_object *obj_priv; int ret = 0; if (!(dev->driver->driver_features & DRIVER_GEM)) @@ -1153,14 +1148,8 @@ i915_gem_sw_finish_ioctl(struct drm_device *dev, void *data, return ret; } -#if WATCH_BUF - DRM_INFO("%s: sw_finish %d (%p %zd)\n", - __func__, args->handle, obj, obj->size); -#endif - obj_priv = to_intel_bo(obj); - /* Pinned buffers may be scanout, so flush the cache */ - if (obj_priv->pin_count) + if (to_intel_bo(obj)->pin_count) i915_gem_object_flush_cpu_write_domain(obj); drm_gem_object_unreference(obj); @@ -2061,10 +2050,6 @@ i915_gem_object_wait_rendering(struct drm_gem_object *obj, * it. */ if (obj_priv->active) { -#if WATCH_BUF - DRM_INFO("%s: object %p wait for seqno %08x\n", - __func__, obj, obj_priv->last_rendering_seqno); -#endif ret = i915_do_wait_request(dev, obj_priv->last_rendering_seqno, interruptible, @@ -2086,10 +2071,6 @@ i915_gem_object_unbind(struct drm_gem_object *obj) struct drm_i915_gem_object *obj_priv = to_intel_bo(obj); int ret = 0; -#if WATCH_BUF - DRM_INFO("%s:%d %p\n", __func__, __LINE__, obj); - DRM_INFO("gtt_space %p\n", obj_priv->gtt_space); -#endif if (obj_priv->gtt_space == NULL) return 0; @@ -2647,10 +2628,6 @@ i915_gem_object_bind_to_gtt(struct drm_gem_object *obj, unsigned alignment) goto search_free; } -#if WATCH_BUF - DRM_INFO("Binding object of size %zd at 0x%08x\n", - obj->size, obj_priv->gtt_offset); -#endif ret = i915_gem_object_get_pages(obj, gfpmask); if (ret) { drm_mm_put_block(obj_priv->gtt_space); @@ -3073,12 +3050,6 @@ i915_gem_object_set_to_gpu_domain(struct drm_gem_object *obj) intel_mark_busy(dev, obj); -#if WATCH_BUF - DRM_INFO("%s: object %p read %08x -> %08x write %08x -> %08x\n", - __func__, obj, - obj->read_domains, obj->pending_read_domains, - obj->write_domain, obj->pending_write_domain); -#endif /* * If the object isn't moving to a new write domain, * let the object stay in multiple read domains @@ -3105,13 +3076,8 @@ i915_gem_object_set_to_gpu_domain(struct drm_gem_object *obj) * stale data. That is, any new read domains. */ invalidate_domains |= obj->pending_read_domains & ~obj->read_domains; - if ((flush_domains | invalidate_domains) & I915_GEM_DOMAIN_CPU) { -#if WATCH_BUF - DRM_INFO("%s: CPU domain flush %08x invalidate %08x\n", - __func__, flush_domains, invalidate_domains); -#endif + if ((flush_domains | invalidate_domains) & I915_GEM_DOMAIN_CPU) i915_gem_clflush_object(obj); - } old_read_domains = obj->read_domains; @@ -3129,12 +3095,6 @@ i915_gem_object_set_to_gpu_domain(struct drm_gem_object *obj) dev->flush_domains |= flush_domains; if (obj_priv->ring) dev_priv->mm.flush_rings |= obj_priv->ring->id; -#if WATCH_BUF - DRM_INFO("%s: read %08x write %08x invalidate %08x flush %08x\n", - __func__, - obj->read_domains, obj->write_domain, - dev->invalidate_domains, dev->flush_domains); -#endif trace_i915_gem_object_change_domain(obj, old_read_domains, @@ -3438,11 +3398,6 @@ i915_gem_object_pin_and_relocate(struct drm_gem_object *obj, (reloc_offset & (PAGE_SIZE - 1))); reloc_val = target_obj_priv->gtt_offset + reloc->delta; -#if WATCH_BUF - DRM_INFO("Applied relocation: %p@0x%08x %08x -> %08x\n", - obj, (unsigned int) reloc->offset, - readl(reloc_entry), reloc_val); -#endif writel(reloc_val, reloc_entry); io_mapping_unmap_atomic(reloc_page, KM_USER0); @@ -3454,10 +3409,6 @@ i915_gem_object_pin_and_relocate(struct drm_gem_object *obj, drm_gem_object_unreference(target_obj); } -#if WATCH_BUF - if (0) - i915_gem_dump_object(obj, 128, __func__, ~0); -#endif return 0; } diff --git a/drivers/gpu/drm/i915/i915_gem_debug.c b/drivers/gpu/drm/i915/i915_gem_debug.c index 26e67ee..2732c90 100644 --- a/drivers/gpu/drm/i915/i915_gem_debug.c +++ b/drivers/gpu/drm/i915/i915_gem_debug.c @@ -52,7 +52,7 @@ i915_verify_inactive(struct drm_device *dev, char *file, int line) #endif /* WATCH_INACTIVE */ -#if WATCH_BUF | WATCH_EXEC | WATCH_PWRITE +#if WATCH_EXEC | WATCH_PWRITE static void i915_gem_dump_page(struct page *page, uint32_t start, uint32_t end, uint32_t bias, uint32_t mark) -- cgit v1.1 From 891b48cfc8659be486c70a03ad815f9a2485ee58 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Wed, 29 Sep 2010 12:26:37 +0100 Subject: drm/i915: Avoid blocking the kworker thread on a stuck mutex Just reschedule the retire requests again if the device is currently busy. The request list will be pruned along other paths so will never grow unbounded and so we can afford to miss the occasional pruning. Signed-off-by: Chris Wilson --- drivers/gpu/drm/i915/i915_gem.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index 9a8e675..fe1424c 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -1901,7 +1901,12 @@ i915_gem_retire_work_handler(struct work_struct *work) mm.retire_work.work); dev = dev_priv->dev; - mutex_lock(&dev->struct_mutex); + /* Come back later if the device is busy... */ + if (!mutex_trylock(&dev->struct_mutex)) { + queue_delayed_work(dev_priv->wq, &dev_priv->mm.retire_work, HZ); + return; + } + i915_gem_retire_requests(dev); if (!dev_priv->mm.suspended && -- cgit v1.1 From 23bc598253fa8e9ede6ad29304ea4ed177e9fc23 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Wed, 29 Sep 2010 16:10:57 +0100 Subject: drm/i915/debug: Convert i915_verify_active() to scan all lists ... and check more regularly. Signed-off-by: Chris Wilson --- drivers/gpu/drm/i915/i915_drv.h | 8 +-- drivers/gpu/drm/i915/i915_gem.c | 29 +++------ drivers/gpu/drm/i915/i915_gem_debug.c | 111 ++++++++++++++++++++++++++++---- drivers/gpu/drm/i915/intel_ringbuffer.c | 4 +- 4 files changed, 113 insertions(+), 39 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index cb4e9a6..5ccf980 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -77,7 +77,7 @@ enum plane { #define WATCH_COHERENCY 0 #define WATCH_EXEC 0 #define WATCH_RELOC 0 -#define WATCH_INACTIVE 0 +#define WATCH_LISTS 0 #define WATCH_PWRITE 0 #define I915_GEM_PHYS_CURSOR_0 1 @@ -1079,10 +1079,10 @@ bool i915_gem_object_fence_offset_ok(struct drm_gem_object *obj, /* i915_gem_debug.c */ void i915_gem_dump_object(struct drm_gem_object *obj, int len, const char *where, uint32_t mark); -#if WATCH_INACTIVE -void i915_verify_inactive(struct drm_device *dev, char *file, int line); +#if WATCH_LISTS +int i915_verify_lists(struct drm_device *dev); #else -#define i915_verify_inactive(dev, file, line) +#define i915_verify_lists(dev) 0 #endif void i915_gem_object_check_coherency(struct drm_gem_object *obj, int handle); void i915_gem_dump_object(struct drm_gem_object *obj, int len, diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index fe1424c..c3a7065 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -109,6 +109,7 @@ static int i915_mutex_lock_interruptible(struct drm_device *dev) return -EAGAIN; } + WARN_ON(i915_verify_lists(dev)); return 0; } @@ -1612,7 +1613,6 @@ i915_gem_object_move_to_inactive(struct drm_gem_object *obj) drm_i915_private_t *dev_priv = dev->dev_private; struct drm_i915_gem_object *obj_priv = to_intel_bo(obj); - i915_verify_inactive(dev, __FILE__, __LINE__); if (obj_priv->pin_count != 0) list_move_tail(&obj_priv->list, &dev_priv->mm.pinned_list); else @@ -1626,7 +1626,7 @@ i915_gem_object_move_to_inactive(struct drm_gem_object *obj) obj_priv->active = 0; drm_gem_object_unreference(obj); } - i915_verify_inactive(dev, __FILE__, __LINE__); + WARN_ON(i915_verify_lists(dev)); } static void @@ -1821,6 +1821,8 @@ i915_gem_retire_requests_ring(struct drm_device *dev, list_empty(&ring->request_list)) return; + WARN_ON(i915_verify_lists(dev)); + seqno = ring->get_seqno(dev, ring); while (!list_empty(&ring->request_list)) { struct drm_i915_gem_request *request; @@ -1865,6 +1867,8 @@ i915_gem_retire_requests_ring(struct drm_device *dev, ring->user_irq_put(dev, ring); dev_priv->trace_irq_seqno = 0; } + + WARN_ON(i915_verify_lists(dev)); } void @@ -3690,8 +3694,6 @@ i915_gem_do_execbuffer(struct drm_device *dev, void *data, if (ret) goto pre_mutex_err; - i915_verify_inactive(dev, __FILE__, __LINE__); - if (dev_priv->mm.suspended) { mutex_unlock(&dev->struct_mutex); ret = -EBUSY; @@ -3811,8 +3813,6 @@ i915_gem_do_execbuffer(struct drm_device *dev, void *data, goto err; } - i915_verify_inactive(dev, __FILE__, __LINE__); - /* Zero the global flush/invalidate flags. These * will be modified as new domains are computed * for each object @@ -3828,8 +3828,6 @@ i915_gem_do_execbuffer(struct drm_device *dev, void *data, i915_gem_object_set_to_gpu_domain(obj); } - i915_verify_inactive(dev, __FILE__, __LINE__); - if (dev->invalidate_domains | dev->flush_domains) { #if WATCH_EXEC DRM_INFO("%s: invalidate_domains %08x flush_domains %08x\n", @@ -3860,8 +3858,6 @@ i915_gem_do_execbuffer(struct drm_device *dev, void *data, old_write_domain); } - i915_verify_inactive(dev, __FILE__, __LINE__); - #if WATCH_COHERENCY for (i = 0; i < args->buffer_count; i++) { i915_gem_object_check_coherency(object_list[i], @@ -3890,8 +3886,6 @@ i915_gem_do_execbuffer(struct drm_device *dev, void *data, */ i915_retire_commands(dev, ring); - i915_verify_inactive(dev, __FILE__, __LINE__); - for (i = 0; i < args->buffer_count; i++) { struct drm_gem_object *obj = object_list[i]; obj_priv = to_intel_bo(obj); @@ -3902,8 +3896,6 @@ i915_gem_do_execbuffer(struct drm_device *dev, void *data, i915_add_request(dev, file_priv, request, ring); request = NULL; - i915_verify_inactive(dev, __FILE__, __LINE__); - err: for (i = 0; i < pinned; i++) i915_gem_object_unpin(object_list[i]); @@ -4094,8 +4086,7 @@ i915_gem_object_pin(struct drm_gem_object *obj, uint32_t alignment) int ret; BUG_ON(obj_priv->pin_count == DRM_I915_GEM_OBJECT_MAX_PIN_COUNT); - - i915_verify_inactive(dev, __FILE__, __LINE__); + WARN_ON(i915_verify_lists(dev)); if (obj_priv->gtt_space != NULL) { if (alignment == 0) @@ -4129,8 +4120,8 @@ i915_gem_object_pin(struct drm_gem_object *obj, uint32_t alignment) list_move_tail(&obj_priv->list, &dev_priv->mm.pinned_list); } - i915_verify_inactive(dev, __FILE__, __LINE__); + WARN_ON(i915_verify_lists(dev)); return 0; } @@ -4141,7 +4132,7 @@ i915_gem_object_unpin(struct drm_gem_object *obj) drm_i915_private_t *dev_priv = dev->dev_private; struct drm_i915_gem_object *obj_priv = to_intel_bo(obj); - i915_verify_inactive(dev, __FILE__, __LINE__); + WARN_ON(i915_verify_lists(dev)); obj_priv->pin_count--; BUG_ON(obj_priv->pin_count < 0); BUG_ON(obj_priv->gtt_space == NULL); @@ -4157,7 +4148,7 @@ i915_gem_object_unpin(struct drm_gem_object *obj) atomic_dec(&dev->pin_count); atomic_sub(obj->size, &dev->pin_memory); } - i915_verify_inactive(dev, __FILE__, __LINE__); + WARN_ON(i915_verify_lists(dev)); } int diff --git a/drivers/gpu/drm/i915/i915_gem_debug.c b/drivers/gpu/drm/i915/i915_gem_debug.c index 2732c90..48644b8 100644 --- a/drivers/gpu/drm/i915/i915_gem_debug.c +++ b/drivers/gpu/drm/i915/i915_gem_debug.c @@ -30,24 +30,107 @@ #include "i915_drm.h" #include "i915_drv.h" -#if WATCH_INACTIVE -void -i915_verify_inactive(struct drm_device *dev, char *file, int line) +#if WATCH_LISTS +int +i915_verify_lists(struct drm_device *dev) { + static int warned; drm_i915_private_t *dev_priv = dev->dev_private; - struct drm_gem_object *obj; - struct drm_i915_gem_object *obj_priv; - - list_for_each_entry(obj_priv, &dev_priv->mm.inactive_list, list) { - obj = &obj_priv->base; - if (obj_priv->pin_count || obj_priv->active || - (obj->write_domain & ~(I915_GEM_DOMAIN_CPU | - I915_GEM_DOMAIN_GTT))) - DRM_ERROR("inactive %p (p %d a %d w %x) %s:%d\n", + struct drm_i915_gem_object *obj; + int err = 0; + + if (warned) + return 0; + + list_for_each_entry(obj, &dev_priv->render_ring.active_list, list) { + if (obj->base.dev != dev || + !atomic_read(&obj->base.refcount.refcount)) { + DRM_ERROR("freed render active %p\n", obj); + err++; + break; + } else if (!obj->active || + (obj->base.read_domains & I915_GEM_GPU_DOMAINS) == 0) { + DRM_ERROR("invalid render active %p (a %d r %x)\n", + obj, + obj->active, + obj->base.read_domains); + err++; + } else if (obj->base.write_domain && list_empty(&obj->gpu_write_list)) { + DRM_ERROR("invalid render active %p (w %x, gwl %d)\n", + obj, + obj->base.write_domain, + !list_empty(&obj->gpu_write_list)); + err++; + } + } + + list_for_each_entry(obj, &dev_priv->mm.flushing_list, list) { + if (obj->base.dev != dev || + !atomic_read(&obj->base.refcount.refcount)) { + DRM_ERROR("freed flushing %p\n", obj); + err++; + break; + } else if (!obj->active || + (obj->base.write_domain & I915_GEM_GPU_DOMAINS) == 0 || + list_empty(&obj->gpu_write_list)){ + DRM_ERROR("invalid flushing %p (a %d w %x gwl %d)\n", + obj, + obj->active, + obj->base.write_domain, + !list_empty(&obj->gpu_write_list)); + err++; + } + } + + list_for_each_entry(obj, &dev_priv->mm.gpu_write_list, gpu_write_list) { + if (obj->base.dev != dev || + !atomic_read(&obj->base.refcount.refcount)) { + DRM_ERROR("freed gpu write %p\n", obj); + err++; + break; + } else if (!obj->active || + (obj->base.write_domain & I915_GEM_GPU_DOMAINS) == 0) { + DRM_ERROR("invalid gpu write %p (a %d w %x)\n", obj, - obj_priv->pin_count, obj_priv->active, - obj->write_domain, file, line); + obj->active, + obj->base.write_domain); + err++; + } + } + + list_for_each_entry(obj, &dev_priv->mm.inactive_list, list) { + if (obj->base.dev != dev || + !atomic_read(&obj->base.refcount.refcount)) { + DRM_ERROR("freed inactive %p\n", obj); + err++; + break; + } else if (obj->pin_count || obj->active || + (obj->base.write_domain & I915_GEM_GPU_DOMAINS)) { + DRM_ERROR("invalid inactive %p (p %d a %d w %x)\n", + obj, + obj->pin_count, obj->active, + obj->base.write_domain); + err++; + } } + + list_for_each_entry(obj, &dev_priv->mm.pinned_list, list) { + if (obj->base.dev != dev || + !atomic_read(&obj->base.refcount.refcount)) { + DRM_ERROR("freed pinned %p\n", obj); + err++; + break; + } else if (!obj->pin_count || obj->active || + (obj->base.write_domain & I915_GEM_GPU_DOMAINS)) { + DRM_ERROR("invalid pinned %p (p %d a %d w %x)\n", + obj, + obj->pin_count, obj->active, + obj->base.write_domain); + err++; + } + } + + return warned = err; } #endif /* WATCH_INACTIVE */ diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.c b/drivers/gpu/drm/i915/intel_ringbuffer.c index 5103b95..d89b887 100644 --- a/drivers/gpu/drm/i915/intel_ringbuffer.c +++ b/drivers/gpu/drm/i915/intel_ringbuffer.c @@ -579,6 +579,8 @@ int intel_init_ring_buffer(struct drm_device *dev, int ret; ring->dev = dev; + INIT_LIST_HEAD(&ring->active_list); + INIT_LIST_HEAD(&ring->request_list); if (I915_NEED_GFX_HWS(dev)) { ret = init_status_page(dev, ring); @@ -627,8 +629,6 @@ int intel_init_ring_buffer(struct drm_device *dev, if (ring->space < 0) ring->space += ring->size; } - INIT_LIST_HEAD(&ring->active_list); - INIT_LIST_HEAD(&ring->request_list); return ret; err_unmap: -- cgit v1.1 From d21d5975686fbc107f9352006b06e1e92b4c5810 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Sun, 26 Sep 2010 11:19:33 +0100 Subject: drm/i915: Report the deferred free list in debugfs Signed-off-by: Chris Wilson --- drivers/gpu/drm/i915/i915_debugfs.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/i915_debugfs.c b/drivers/gpu/drm/i915/i915_debugfs.c index eb5dd52..e489398 100644 --- a/drivers/gpu/drm/i915/i915_debugfs.c +++ b/drivers/gpu/drm/i915/i915_debugfs.c @@ -45,7 +45,8 @@ enum { BSD_LIST, FLUSHING_LIST, INACTIVE_LIST, - PINNED_LIST + PINNED_LIST, + DEFERRED_FREE_LIST, }; static const char *yesno(int v) @@ -161,6 +162,10 @@ static int i915_gem_object_list_info(struct seq_file *m, void *data) seq_printf(m, "Flushing:\n"); head = &dev_priv->mm.flushing_list; break; + case DEFERRED_FREE_LIST: + seq_printf(m, "Deferred free:\n"); + head = &dev_priv->mm.deferred_free_list; + break; default: mutex_unlock(&dev->struct_mutex); return -EINVAL; @@ -991,6 +996,7 @@ static struct drm_info_list i915_debugfs_list[] = { {"i915_gem_flushing", i915_gem_object_list_info, 0, (void *) FLUSHING_LIST}, {"i915_gem_inactive", i915_gem_object_list_info, 0, (void *) INACTIVE_LIST}, {"i915_gem_pinned", i915_gem_object_list_info, 0, (void *) PINNED_LIST}, + {"i915_gem_deferred_free", i915_gem_object_list_info, 0, (void *) DEFERRED_FREE_LIST}, {"i915_gem_pageflip", i915_gem_pageflip_info, 0}, {"i915_gem_request", i915_gem_request_info, 0}, {"i915_gem_seqno", i915_gem_seqno_info, 0}, -- cgit v1.1 From 8f2480fb05991f1a5522dd48332cd9db4f7745c6 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Sun, 26 Sep 2010 11:44:19 +0100 Subject: drm/i915/debugfs: Include list totals Signed-off-by: Chris Wilson --- drivers/gpu/drm/i915/i915_debugfs.c | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_debugfs.c b/drivers/gpu/drm/i915/i915_debugfs.c index e489398..47e3a8f 100644 --- a/drivers/gpu/drm/i915/i915_debugfs.c +++ b/drivers/gpu/drm/i915/i915_debugfs.c @@ -135,7 +135,8 @@ static int i915_gem_object_list_info(struct seq_file *m, void *data) struct drm_device *dev = node->minor->dev; drm_i915_private_t *dev_priv = dev->dev_private; struct drm_i915_gem_object *obj_priv; - int ret; + size_t total_obj_size, total_gtt_size; + int count, ret; ret = mutex_lock_interruptible(&dev->struct_mutex); if (ret) @@ -171,13 +172,19 @@ static int i915_gem_object_list_info(struct seq_file *m, void *data) return -EINVAL; } + total_obj_size = total_gtt_size = count = 0; list_for_each_entry(obj_priv, head, list) { seq_printf(m, " "); describe_obj(m, obj_priv); seq_printf(m, "\n"); + total_obj_size += obj_priv->base.size; + total_gtt_size += obj_priv->gtt_space->size; + count++; } - mutex_unlock(&dev->struct_mutex); + + seq_printf(m, "Total %d objects, %zu bytes, %zu GTT size\n", + count, total_obj_size, total_gtt_size); return 0; } -- cgit v1.1 From 5cdf58817433345157644140f2f509f00c06d479 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Mon, 27 Sep 2010 15:51:07 +0100 Subject: drm/i915: Make get/put pages static Signed-off-by: Chris Wilson --- drivers/gpu/drm/i915/i915_debugfs.c | 26 +++++++++++--------------- drivers/gpu/drm/i915/i915_drv.h | 2 -- drivers/gpu/drm/i915/i915_gem.c | 13 ++++++++++--- 3 files changed, 21 insertions(+), 20 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_debugfs.c b/drivers/gpu/drm/i915/i915_debugfs.c index 47e3a8f..0d9bbd5 100644 --- a/drivers/gpu/drm/i915/i915_debugfs.c +++ b/drivers/gpu/drm/i915/i915_debugfs.c @@ -406,16 +406,19 @@ static int i915_hws_info(struct seq_file *m, void *data) return 0; } -static void i915_dump_pages(struct seq_file *m, struct page **pages, int page_count) +static void i915_dump_object(struct seq_file *m, + struct io_mapping *mapping, + struct drm_i915_gem_object *obj_priv) { - int page, i; - uint32_t *mem; + int page, page_count, i; + page_count = obj_priv->base.size / PAGE_SIZE; for (page = 0; page < page_count; page++) { - mem = kmap(pages[page]); + u32 *mem = io_mapping_map_wc(mapping, + obj_priv->gtt_offset + page * PAGE_SIZE); for (i = 0; i < PAGE_SIZE; i += 4) seq_printf(m, "%08x : %08x\n", i, mem[i / 4]); - kunmap(pages[page]); + io_mapping_unmap(mem); } } @@ -436,16 +439,9 @@ static int i915_batchbuffer_info(struct seq_file *m, void *data) list) { obj = &obj_priv->base; if (obj->read_domains & I915_GEM_DOMAIN_COMMAND) { - ret = i915_gem_object_get_pages(obj, 0); - if (ret) { - mutex_unlock(&dev->struct_mutex); - return ret; - } - - seq_printf(m, "--- gtt_offset = 0x%08x\n", obj_priv->gtt_offset); - i915_dump_pages(m, obj_priv->pages, obj->size / PAGE_SIZE); - - i915_gem_object_put_pages(obj); + seq_printf(m, "--- gtt_offset = 0x%08x\n", + obj_priv->gtt_offset); + i915_dump_object(m, dev_priv->mm.gtt_mapping, obj_priv); } } diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 5ccf980..66acc7c 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -1055,8 +1055,6 @@ int i915_gem_attach_phys_object(struct drm_device *dev, void i915_gem_detach_phys_object(struct drm_device *dev, struct drm_gem_object *obj); void i915_gem_free_all_phys_object(struct drm_device *dev); -int i915_gem_object_get_pages(struct drm_gem_object *obj, gfp_t gfpmask); -void i915_gem_object_put_pages(struct drm_gem_object *obj); void i915_gem_release(struct drm_device * dev, struct drm_file *file_priv); void i915_gem_shrinker_init(void); diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index c3a7065..613b0bf 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -58,6 +58,13 @@ static int i915_gem_phys_pwrite(struct drm_device *dev, struct drm_gem_object *o struct drm_file *file_priv); static void i915_gem_free_object_tail(struct drm_gem_object *obj); +static int +i915_gem_object_get_pages(struct drm_gem_object *obj, + gfp_t gfpmask); + +static void +i915_gem_object_put_pages(struct drm_gem_object *obj); + static LIST_HEAD(shrink_list); static DEFINE_SPINLOCK(shrink_list_lock); @@ -1021,7 +1028,7 @@ i915_gem_pwrite_ioctl(struct drm_device *dev, void *data, if (obj_priv->phys_obj) ret = i915_gem_phys_pwrite(dev, obj, args, file_priv); else if (obj_priv->tiling_mode == I915_TILING_NONE && - dev->gtt_total != 0 && + obj_priv->gtt_space && obj->write_domain != I915_GEM_DOMAIN_CPU) { ret = i915_gem_gtt_pwrite_fast(dev, obj, args, file_priv); if (ret == -EFAULT) { @@ -1501,7 +1508,7 @@ i915_gem_mmap_gtt_ioctl(struct drm_device *dev, void *data, return 0; } -void +static void i915_gem_object_put_pages(struct drm_gem_object *obj) { struct drm_i915_gem_object *obj_priv = to_intel_bo(obj); @@ -2174,7 +2181,7 @@ i915_gpu_idle(struct drm_device *dev) return 0; } -int +static int i915_gem_object_get_pages(struct drm_gem_object *obj, gfp_t gfpmask) { -- cgit v1.1 From f394940b8d275064f080a59dac636688dae3531a Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Wed, 29 Sep 2010 21:19:54 +0100 Subject: drm/i915: Remove redundant deletion of obj->gpu_write_list At that point as the object is no longer in any GPU write domain it must not be on the list, so the list_del() is redundant. Signed-off-by: Chris Wilson --- drivers/gpu/drm/i915/i915_gem.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index 613b0bf..302beee 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -3857,8 +3857,6 @@ i915_gem_do_execbuffer(struct drm_device *dev, void *data, if (obj->write_domain) list_move_tail(&obj_priv->gpu_write_list, &dev_priv->mm.gpu_write_list); - else - list_del_init(&obj_priv->gpu_write_list); trace_i915_gem_object_change_domain(obj, obj->read_domains, -- cgit v1.1 From 6a04002bea137d2c6359228316d9c827806e475f Mon Sep 17 00:00:00 2001 From: Simon Que Date: Thu, 30 Sep 2010 09:36:39 +0100 Subject: i915: Added function to initialize VBT settings Added a function that sets the LVDS values to default settings. This will be called by intel_init_bios before checking for the VBT (video BIOS table). The default values are thus loaded regardless of whether a VBT is found. The default settings in each parse function have been moved to the new function. This consolidates all the default settings into one place. The default dither bit value has been changed from 0 to 1. We can assume that display devices will want dithering enabled. Signed-off-by: Simon Que Acked-by: Olof Johansson [ickle: fixup for -next] Signed-off-by: Chris Wilson --- drivers/gpu/drm/i915/intel_bios.c | 36 +++++++++++++++++++++++------------- 1 file changed, 23 insertions(+), 13 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_bios.c b/drivers/gpu/drm/i915/intel_bios.c index 7e868d2..b1f73ac 100644 --- a/drivers/gpu/drm/i915/intel_bios.c +++ b/drivers/gpu/drm/i915/intel_bios.c @@ -129,10 +129,6 @@ parse_lfp_panel_data(struct drm_i915_private *dev_priv, int i, temp_downclock; struct drm_display_mode *temp_mode; - /* Defaults if we can't find VBT info */ - dev_priv->lvds_dither = 0; - dev_priv->lvds_vbt = 0; - lvds_options = find_section(bdb, BDB_LVDS_OPTIONS); if (!lvds_options) return; @@ -140,6 +136,7 @@ parse_lfp_panel_data(struct drm_i915_private *dev_priv, dev_priv->lvds_dither = lvds_options->pixel_dither; if (lvds_options->panel_type == 0xff) return; + panel_type = lvds_options->panel_type; lvds_lfp_data = find_section(bdb, BDB_LVDS_LFP_DATA); @@ -232,8 +229,6 @@ parse_sdvo_panel_data(struct drm_i915_private *dev_priv, struct lvds_dvo_timing *dvo_timing; struct drm_display_mode *panel_fixed_mode; - dev_priv->sdvo_lvds_vbt_mode = NULL; - sdvo_lvds_options = find_section(bdb, BDB_SDVO_LVDS_OPTIONS); if (!sdvo_lvds_options) return; @@ -262,10 +257,6 @@ parse_general_features(struct drm_i915_private *dev_priv, struct drm_device *dev = dev_priv->dev; struct bdb_general_features *general; - /* Set sensible defaults in case we can't find the general block */ - dev_priv->int_tv_support = 1; - dev_priv->int_crt_support = 1; - general = find_section(bdb, BDB_GENERAL_FEATURES); if (general) { dev_priv->int_tv_support = general->int_tv_support; @@ -423,8 +414,6 @@ parse_edp(struct drm_i915_private *dev_priv, struct bdb_header *bdb) { struct bdb_edp *edp; - dev_priv->edp.bpp = 18; - edp = find_section(bdb, BDB_EDP); if (!edp) { if (SUPPORTS_EDP(dev_priv->dev) && dev_priv->edp.support) { @@ -528,6 +517,27 @@ parse_device_mapping(struct drm_i915_private *dev_priv, return; } +static void +init_vbt_defaults(struct drm_i915_private *dev_priv) +{ + dev_priv->crt_ddc_pin = GMBUS_PORT_VGADDC; + + /* LFP panel data */ + dev_priv->lvds_dither = 1; + dev_priv->lvds_vbt = 0; + + /* SDVO panel data */ + dev_priv->sdvo_lvds_vbt_mode = NULL; + + /* general features */ + dev_priv->int_tv_support = 1; + dev_priv->int_crt_support = 1; + dev_priv->lvds_use_ssc = 0; + + /* eDP data */ + dev_priv->edp.bpp = 18; +} + /** * intel_init_bios - initialize VBIOS settings & find VBT * @dev: DRM device @@ -545,7 +555,7 @@ intel_init_bios(struct drm_device *dev) struct bdb_header *bdb = NULL; u8 __iomem *bios = NULL; - dev_priv->crt_ddc_pin = GMBUS_PORT_VGADDC; + init_vbt_defaults(dev_priv); /* XXX Should this validation be moved to intel_opregion.c? */ if (dev_priv->opregion.vbt) { -- cgit v1.1 From e39a01501b228e1be2037d5bddccae2a820af902 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Wed, 29 Sep 2010 22:23:05 +0100 Subject: drm/i915: Fix refleak during eviction. Now that we hold onto a reference whilst evicting objects, we need to be sure that we drop all the references taken -- even on the error paths. Signed-off-by: Chris Wilson --- drivers/gpu/drm/i915/i915_gem_evict.c | 45 ++++++++++++++++------------------- 1 file changed, 20 insertions(+), 25 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_gem_evict.c b/drivers/gpu/drm/i915/i915_gem_evict.c index e85246e..5c428fa 100644 --- a/drivers/gpu/drm/i915/i915_gem_evict.c +++ b/drivers/gpu/drm/i915/i915_gem_evict.c @@ -93,7 +93,7 @@ i915_gem_evict_something(struct drm_device *dev, int min_size, unsigned alignmen { drm_i915_private_t *dev_priv = dev->dev_private; struct list_head eviction_list, unwind_list; - struct drm_i915_gem_object *obj_priv, *tmp_obj_priv; + struct drm_i915_gem_object *obj_priv; struct list_head *render_iter, *bsd_iter; int ret = 0; @@ -175,39 +175,34 @@ i915_gem_evict_something(struct drm_device *dev, int min_size, unsigned alignmen return -ENOSPC; found: + /* drm_mm doesn't allow any other other operations while + * scanning, therefore store to be evicted objects on a + * temporary list. */ INIT_LIST_HEAD(&eviction_list); - list_for_each_entry_safe(obj_priv, tmp_obj_priv, - &unwind_list, evict_list) { + while (!list_empty(&unwind_list)) { + obj_priv = list_first_entry(&unwind_list, + struct drm_i915_gem_object, + evict_list); if (drm_mm_scan_remove_block(obj_priv->gtt_space)) { - /* drm_mm doesn't allow any other other operations while - * scanning, therefore store to be evicted objects on a - * temporary list. */ list_move(&obj_priv->evict_list, &eviction_list); - } else - drm_gem_object_unreference(&obj_priv->base); + continue; + } + list_del(&obj_priv->evict_list); + drm_gem_object_unreference(&obj_priv->base); } /* Unbinding will emit any required flushes */ - list_for_each_entry_safe(obj_priv, tmp_obj_priv, - &eviction_list, evict_list) { -#if WATCH_LRU - DRM_INFO("%s: evicting %p\n", __func__, &obj_priv->base); -#endif - ret = i915_gem_object_unbind(&obj_priv->base); - if (ret) - return ret; - + while (!list_empty(&eviction_list)) { + obj_priv = list_first_entry(&eviction_list, + struct drm_i915_gem_object, + evict_list); + if (ret == 0) + ret = i915_gem_object_unbind(&obj_priv->base); + list_del(&obj_priv->evict_list); drm_gem_object_unreference(&obj_priv->base); } - /* The just created free hole should be on the top of the free stack - * maintained by drm_mm, so this BUG_ON actually executes in O(1). - * Furthermore all accessed data has just recently been used, so it - * should be really fast, too. */ - BUG_ON(!drm_mm_search_free(&dev_priv->mm.gtt_space, min_size, - alignment, 0)); - - return 0; + return ret; } int -- cgit v1.1 From 73aa808f10effc280e6eb70267314542a7c29426 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Thu, 30 Sep 2010 11:46:12 +0100 Subject: drm: Move the GTT accounting to i915 Only drm/i915 does the bookkeeping that makes the information useful, and the information maintained is driver specific, so move it out of the core and into its single user. Signed-off-by: Chris Wilson Cc: Dave Airlie --- drivers/gpu/drm/drm_debugfs.c | 1 - drivers/gpu/drm/drm_gem.c | 14 ----- drivers/gpu/drm/drm_info.c | 14 ----- drivers/gpu/drm/drm_proc.c | 1 - drivers/gpu/drm/i915/i915_debugfs.c | 26 +++++++++ drivers/gpu/drm/i915/i915_drv.h | 9 +++ drivers/gpu/drm/i915/i915_gem.c | 110 +++++++++++++++++++++++++----------- include/drm/drmP.h | 8 --- 8 files changed, 111 insertions(+), 72 deletions(-) diff --git a/drivers/gpu/drm/drm_debugfs.c b/drivers/gpu/drm/drm_debugfs.c index 677b275..9d8c892 100644 --- a/drivers/gpu/drm/drm_debugfs.c +++ b/drivers/gpu/drm/drm_debugfs.c @@ -48,7 +48,6 @@ static struct drm_info_list drm_debugfs_list[] = { {"queues", drm_queues_info, 0}, {"bufs", drm_bufs_info, 0}, {"gem_names", drm_gem_name_info, DRIVER_GEM}, - {"gem_objects", drm_gem_object_info, DRIVER_GEM}, #if DRM_DEBUG_CODE {"vma", drm_vma_info, 0}, #endif diff --git a/drivers/gpu/drm/drm_gem.c b/drivers/gpu/drm/drm_gem.c index cff7317..3ea0692 100644 --- a/drivers/gpu/drm/drm_gem.c +++ b/drivers/gpu/drm/drm_gem.c @@ -92,12 +92,6 @@ drm_gem_init(struct drm_device *dev) spin_lock_init(&dev->object_name_lock); idr_init(&dev->object_name_idr); - atomic_set(&dev->object_count, 0); - atomic_set(&dev->object_memory, 0); - atomic_set(&dev->pin_count, 0); - atomic_set(&dev->pin_memory, 0); - atomic_set(&dev->gtt_count, 0); - atomic_set(&dev->gtt_memory, 0); mm = kzalloc(sizeof(struct drm_gem_mm), GFP_KERNEL); if (!mm) { @@ -151,9 +145,6 @@ int drm_gem_object_init(struct drm_device *dev, kref_init(&obj->handlecount); obj->size = size; - atomic_inc(&dev->object_count); - atomic_add(obj->size, &dev->object_memory); - return 0; } EXPORT_SYMBOL(drm_gem_object_init); @@ -180,8 +171,6 @@ drm_gem_object_alloc(struct drm_device *dev, size_t size) return obj; fput: /* Object_init mangles the global counters - readjust them. */ - atomic_dec(&dev->object_count); - atomic_sub(obj->size, &dev->object_memory); fput(obj->filp); free: kfree(obj); @@ -436,10 +425,7 @@ drm_gem_release(struct drm_device *dev, struct drm_file *file_private) void drm_gem_object_release(struct drm_gem_object *obj) { - struct drm_device *dev = obj->dev; fput(obj->filp); - atomic_dec(&dev->object_count); - atomic_sub(obj->size, &dev->object_memory); } EXPORT_SYMBOL(drm_gem_object_release); diff --git a/drivers/gpu/drm/drm_info.c b/drivers/gpu/drm/drm_info.c index 2ef2c78..5aff08e 100644 --- a/drivers/gpu/drm/drm_info.c +++ b/drivers/gpu/drm/drm_info.c @@ -270,20 +270,6 @@ int drm_gem_name_info(struct seq_file *m, void *data) return 0; } -int drm_gem_object_info(struct seq_file *m, void* data) -{ - struct drm_info_node *node = (struct drm_info_node *) m->private; - struct drm_device *dev = node->minor->dev; - - seq_printf(m, "%d objects\n", atomic_read(&dev->object_count)); - seq_printf(m, "%d object bytes\n", atomic_read(&dev->object_memory)); - seq_printf(m, "%d pinned\n", atomic_read(&dev->pin_count)); - seq_printf(m, "%d pin bytes\n", atomic_read(&dev->pin_memory)); - seq_printf(m, "%d gtt bytes\n", atomic_read(&dev->gtt_memory)); - seq_printf(m, "%d gtt total\n", dev->gtt_total); - return 0; -} - #if DRM_DEBUG_CODE int drm_vma_info(struct seq_file *m, void *data) diff --git a/drivers/gpu/drm/drm_proc.c b/drivers/gpu/drm/drm_proc.c index e571de5..9e5b07ef 100644 --- a/drivers/gpu/drm/drm_proc.c +++ b/drivers/gpu/drm/drm_proc.c @@ -55,7 +55,6 @@ static struct drm_info_list drm_proc_list[] = { {"queues", drm_queues_info, 0}, {"bufs", drm_bufs_info, 0}, {"gem_names", drm_gem_name_info, DRIVER_GEM}, - {"gem_objects", drm_gem_object_info, DRIVER_GEM}, #if DRM_DEBUG_CODE {"vma", drm_vma_info, 0}, #endif diff --git a/drivers/gpu/drm/i915/i915_debugfs.c b/drivers/gpu/drm/i915/i915_debugfs.c index 0d9bbd5..d598070f 100644 --- a/drivers/gpu/drm/i915/i915_debugfs.c +++ b/drivers/gpu/drm/i915/i915_debugfs.c @@ -188,6 +188,31 @@ static int i915_gem_object_list_info(struct seq_file *m, void *data) return 0; } +static int i915_gem_object_info(struct seq_file *m, void* data) +{ + struct drm_info_node *node = (struct drm_info_node *) m->private; + struct drm_device *dev = node->minor->dev; + struct drm_i915_private *dev_priv = dev->dev_private; + int ret; + + ret = mutex_lock_interruptible(&dev->struct_mutex); + if (ret) + return ret; + + seq_printf(m, "%u objects\n", dev_priv->mm.object_count); + seq_printf(m, "%zu object bytes\n", dev_priv->mm.object_memory); + seq_printf(m, "%u pinned\n", dev_priv->mm.pin_count); + seq_printf(m, "%zu pin bytes\n", dev_priv->mm.pin_memory); + seq_printf(m, "%u objects in gtt\n", dev_priv->mm.gtt_count); + seq_printf(m, "%zu gtt bytes\n", dev_priv->mm.gtt_memory); + seq_printf(m, "%zu gtt total\n", dev_priv->mm.gtt_total); + + mutex_unlock(&dev->struct_mutex); + + return 0; +} + + static int i915_gem_pageflip_info(struct seq_file *m, void *data) { struct drm_info_node *node = (struct drm_info_node *) m->private; @@ -994,6 +1019,7 @@ static int i915_wedged_create(struct dentry *root, struct drm_minor *minor) static struct drm_info_list i915_debugfs_list[] = { {"i915_capabilities", i915_capabilities, 0, 0}, + {"i915_gem_objects", i915_gem_object_info, 0}, {"i915_gem_render_active", i915_gem_object_list_info, 0, (void *) RENDER_LIST}, {"i915_gem_bsd_active", i915_gem_object_list_info, 0, (void *) BSD_LIST}, {"i915_gem_flushing", i915_gem_object_list_info, 0, (void *) FLUSHING_LIST}, diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 66acc7c..7cfbc0f 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -642,6 +642,15 @@ typedef struct drm_i915_private { struct drm_i915_gem_phys_object *phys_objs[I915_MAX_PHYS_OBJECT]; uint32_t flush_rings; + + /* accounting, useful for userland debugging */ + size_t object_memory; + size_t pin_memory; + size_t gtt_memory; + size_t gtt_total; + u32 object_count; + u32 pin_count; + u32 gtt_count; } mm; struct sdvo_device_mapping sdvo_mappings[2]; /* indicate whether the LVDS_BORDER should be enabled or not */ diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index 302beee..16c4b7b 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -68,6 +68,49 @@ i915_gem_object_put_pages(struct drm_gem_object *obj); static LIST_HEAD(shrink_list); static DEFINE_SPINLOCK(shrink_list_lock); +/* some bookkeeping */ +static void i915_gem_info_add_obj(struct drm_i915_private *dev_priv, + size_t size) +{ + dev_priv->mm.object_count++; + dev_priv->mm.object_memory += size; +} + +static void i915_gem_info_remove_obj(struct drm_i915_private *dev_priv, + size_t size) +{ + dev_priv->mm.object_count--; + dev_priv->mm.object_memory -= size; +} + +static void i915_gem_info_add_gtt(struct drm_i915_private *dev_priv, + size_t size) +{ + dev_priv->mm.gtt_count++; + dev_priv->mm.gtt_memory += size; +} + +static void i915_gem_info_remove_gtt(struct drm_i915_private *dev_priv, + size_t size) +{ + dev_priv->mm.gtt_count--; + dev_priv->mm.gtt_memory -= size; +} + +static void i915_gem_info_add_pin(struct drm_i915_private *dev_priv, + size_t size) +{ + dev_priv->mm.pin_count++; + dev_priv->mm.pin_memory += size; +} + +static void i915_gem_info_remove_pin(struct drm_i915_private *dev_priv, + size_t size) +{ + dev_priv->mm.pin_count--; + dev_priv->mm.pin_memory -= size; +} + int i915_gem_check_is_wedged(struct drm_device *dev) { @@ -128,7 +171,8 @@ i915_gem_object_is_inactive(struct drm_i915_gem_object *obj_priv) obj_priv->pin_count == 0; } -int i915_gem_do_init(struct drm_device *dev, unsigned long start, +int i915_gem_do_init(struct drm_device *dev, + unsigned long start, unsigned long end) { drm_i915_private_t *dev_priv = dev->dev_private; @@ -142,7 +186,7 @@ int i915_gem_do_init(struct drm_device *dev, unsigned long start, drm_mm_init(&dev_priv->mm.gtt_space, start, end - start); - dev->gtt_total = (uint32_t) (end - start); + dev_priv->mm.gtt_total = end - start; return 0; } @@ -165,14 +209,16 @@ int i915_gem_get_aperture_ioctl(struct drm_device *dev, void *data, struct drm_file *file_priv) { + struct drm_i915_private *dev_priv = dev->dev_private; struct drm_i915_gem_get_aperture *args = data; if (!(dev->driver->driver_features & DRIVER_GEM)) return -ENODEV; - args->aper_size = dev->gtt_total; - args->aper_available_size = (args->aper_size - - atomic_read(&dev->pin_memory)); + mutex_lock(&dev->struct_mutex); + args->aper_size = dev_priv->mm.gtt_total; + args->aper_available_size = args->aper_size - dev_priv->mm.pin_memory; + mutex_unlock(&dev->struct_mutex); return 0; } @@ -2084,6 +2130,7 @@ int i915_gem_object_unbind(struct drm_gem_object *obj) { struct drm_device *dev = obj->dev; + struct drm_i915_private *dev_priv = dev->dev_private; struct drm_i915_gem_object *obj_priv = to_intel_bo(obj); int ret = 0; @@ -2116,25 +2163,18 @@ i915_gem_object_unbind(struct drm_gem_object *obj) if (obj_priv->fence_reg != I915_FENCE_REG_NONE) i915_gem_clear_fence_reg(obj); - if (obj_priv->agp_mem != NULL) { - drm_unbind_agp(obj_priv->agp_mem); - drm_free_agp(obj_priv->agp_mem, obj->size / PAGE_SIZE); - obj_priv->agp_mem = NULL; - } + drm_unbind_agp(obj_priv->agp_mem); + drm_free_agp(obj_priv->agp_mem, obj->size / PAGE_SIZE); i915_gem_object_put_pages(obj); BUG_ON(obj_priv->pages_refcount); - if (obj_priv->gtt_space) { - atomic_dec(&dev->gtt_count); - atomic_sub(obj->size, &dev->gtt_memory); - - drm_mm_put_block(obj_priv->gtt_space); - obj_priv->gtt_space = NULL; - } - + i915_gem_info_remove_gtt(dev_priv, obj->size); list_del_init(&obj_priv->list); + drm_mm_put_block(obj_priv->gtt_space); + obj_priv->gtt_space = NULL; + if (i915_gem_object_is_purgeable(obj_priv)) i915_gem_object_truncate(obj); @@ -2619,7 +2659,7 @@ i915_gem_object_bind_to_gtt(struct drm_gem_object *obj, unsigned alignment) /* If the object is bigger than the entire aperture, reject it early * before evicting everything in a vain attempt to find space. */ - if (obj->size > dev->gtt_total) { + if (obj->size > dev_priv->mm.gtt_total) { DRM_ERROR("Attempting to bind an object larger than the aperture\n"); return -E2BIG; } @@ -2688,11 +2728,10 @@ i915_gem_object_bind_to_gtt(struct drm_gem_object *obj, unsigned alignment) goto search_free; } - atomic_inc(&dev->gtt_count); - atomic_add(obj->size, &dev->gtt_memory); /* keep track of bounds object by adding it to the inactive list */ list_add_tail(&obj_priv->list, &dev_priv->mm.inactive_list); + i915_gem_info_add_gtt(dev_priv, obj->size); /* Assert that the object is not currently in any GPU domain. As it * wasn't in the GTT, there shouldn't be any way it could have been in @@ -3779,15 +3818,16 @@ i915_gem_do_execbuffer(struct drm_device *dev, void *data, pinned+1, args->buffer_count, total_size, num_fences, ret); - DRM_ERROR("%d objects [%d pinned], " - "%d object bytes [%d pinned], " - "%d/%d gtt bytes\n", - atomic_read(&dev->object_count), - atomic_read(&dev->pin_count), - atomic_read(&dev->object_memory), - atomic_read(&dev->pin_memory), - atomic_read(&dev->gtt_memory), - dev->gtt_total); + DRM_ERROR("%u objects [%u pinned, %u GTT], " + "%zu object bytes [%zu pinned], " + "%zu /%zu gtt bytes\n", + dev_priv->mm.object_count, + dev_priv->mm.pin_count, + dev_priv->mm.gtt_count, + dev_priv->mm.object_memory, + dev_priv->mm.pin_memory, + dev_priv->mm.gtt_memory, + dev_priv->mm.gtt_total); } goto err; } @@ -4119,8 +4159,7 @@ i915_gem_object_pin(struct drm_gem_object *obj, uint32_t alignment) * remove it from the inactive list */ if (obj_priv->pin_count == 1) { - atomic_inc(&dev->pin_count); - atomic_add(obj->size, &dev->pin_memory); + i915_gem_info_add_pin(dev_priv, obj->size); if (!obj_priv->active) list_move_tail(&obj_priv->list, &dev_priv->mm.pinned_list); @@ -4150,8 +4189,7 @@ i915_gem_object_unpin(struct drm_gem_object *obj) if (!obj_priv->active) list_move_tail(&obj_priv->list, &dev_priv->mm.inactive_list); - atomic_dec(&dev->pin_count); - atomic_sub(obj->size, &dev->pin_memory); + i915_gem_info_remove_pin(dev_priv, obj->size); } WARN_ON(i915_verify_lists(dev)); } @@ -4378,6 +4416,7 @@ i915_gem_madvise_ioctl(struct drm_device *dev, void *data, struct drm_gem_object * i915_gem_alloc_object(struct drm_device *dev, size_t size) { + struct drm_i915_private *dev_priv = dev->dev_private; struct drm_i915_gem_object *obj; obj = kzalloc(sizeof(*obj), GFP_KERNEL); @@ -4389,6 +4428,8 @@ struct drm_gem_object * i915_gem_alloc_object(struct drm_device *dev, return NULL; } + i915_gem_info_add_obj(dev_priv, size); + obj->base.write_domain = I915_GEM_DOMAIN_CPU; obj->base.read_domains = I915_GEM_DOMAIN_CPU; @@ -4429,6 +4470,7 @@ static void i915_gem_free_object_tail(struct drm_gem_object *obj) i915_gem_free_mmap_offset(obj); drm_gem_object_release(obj); + i915_gem_info_remove_obj(dev_priv, obj->size); kfree(obj_priv->page_cpu_valid); kfree(obj_priv->bit_17); diff --git a/include/drm/drmP.h b/include/drm/drmP.h index 30e827a..bb5c418 100644 --- a/include/drm/drmP.h +++ b/include/drm/drmP.h @@ -1041,13 +1041,6 @@ struct drm_device { /*@{ */ spinlock_t object_name_lock; struct idr object_name_idr; - atomic_t object_count; - atomic_t object_memory; - atomic_t pin_count; - atomic_t pin_memory; - atomic_t gtt_count; - atomic_t gtt_memory; - uint32_t gtt_total; uint32_t invalidate_domains; /* domains pending invalidation */ uint32_t flush_domains; /* domains pending flush */ /*@} */ @@ -1378,7 +1371,6 @@ extern int drm_bufs_info(struct seq_file *m, void *data); extern int drm_vblank_info(struct seq_file *m, void *data); extern int drm_clients_info(struct seq_file *m, void* data); extern int drm_gem_name_info(struct seq_file *m, void *data); -extern int drm_gem_object_info(struct seq_file *m, void* data); #if DRM_DEBUG_CODE extern int drm_vma_info(struct seq_file *m, void *data); -- cgit v1.1 From 812ed4924328adf94f45c664b6a4c710a69167e2 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Thu, 30 Sep 2010 15:08:57 +0100 Subject: drm/i915: Force the domain to CPU on unbinding whilst wedged. Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=30083 Reported-by: Sitsofe Wheeler Signed-off-by: Chris Wilson --- drivers/gpu/drm/i915/i915_gem.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index 16c4b7b..c033c5a 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -2158,6 +2158,10 @@ i915_gem_object_unbind(struct drm_gem_object *obj) * should be safe and we need to cleanup or else we might * cause memory corruption through use-after-free. */ + if (ret) { + i915_gem_clflush_object(obj); + obj->read_domains = obj->write_domain = I915_GEM_DOMAIN_CPU; + } /* release the fence reg _after_ flushing */ if (obj_priv->fence_reg != I915_FENCE_REG_NONE) -- cgit v1.1 From 069efc1dac477a4a51e42c0fe50bdcf85ada626a Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Thu, 30 Sep 2010 16:53:18 +0100 Subject: drm/i915: Clear fence registers on GPU reset When the GPU is reset, the fence registers are invalidated, so release the objects and clear them out. Signed-off-by: Chris Wilson --- drivers/gpu/drm/i915/i915_drv.c | 2 +- drivers/gpu/drm/i915/i915_drv.h | 2 +- drivers/gpu/drm/i915/i915_gem.c | 14 +++++++++++++- 3 files changed, 15 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_drv.c b/drivers/gpu/drm/i915/i915_drv.c index 2184d29..2109537 100644 --- a/drivers/gpu/drm/i915/i915_drv.c +++ b/drivers/gpu/drm/i915/i915_drv.c @@ -395,7 +395,7 @@ int i915_reset(struct drm_device *dev, u8 flags) mutex_lock(&dev->struct_mutex); - i915_gem_reset_lists(dev); + i915_gem_reset(dev); /* * Set the domains we want to reset (GRDOM/bits 2 and 3) as diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 7cfbc0f..d19a26af 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -1033,7 +1033,7 @@ int i915_gem_object_get_fence_reg(struct drm_gem_object *obj, int i915_gem_object_put_fence_reg(struct drm_gem_object *obj, bool interruptible); void i915_gem_retire_requests(struct drm_device *dev); -void i915_gem_reset_lists(struct drm_device *dev); +void i915_gem_reset(struct drm_device *dev); void i915_gem_clflush_object(struct drm_gem_object *obj); int i915_gem_object_set_domain(struct drm_gem_object *obj, uint32_t read_domains, diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index c033c5a..db9d36f 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -1826,10 +1826,11 @@ static void i915_gem_reset_ring_lists(struct drm_i915_private *dev_priv, } } -void i915_gem_reset_lists(struct drm_device *dev) +void i915_gem_reset(struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; struct drm_i915_gem_object *obj_priv; + int i; i915_gem_reset_ring_lists(dev_priv, &dev_priv->render_ring); if (HAS_BSD(dev)) @@ -1858,6 +1859,17 @@ void i915_gem_reset_lists(struct drm_device *dev) { obj_priv->base.read_domains &= ~I915_GEM_GPU_DOMAINS; } + + /* The fence registers are invalidated so clear them out */ + for (i = 0; i < 16; i++) { + struct drm_i915_fence_reg *reg; + + reg = &dev_priv->fence_regs[i]; + if (!reg->obj) + continue; + + i915_gem_clear_fence_reg(reg->obj); + } } /** -- cgit v1.1 From dc96e9b8e37641d9d15a8a4cdd18ed7680d8f546 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Fri, 1 Oct 2010 12:05:06 +0100 Subject: drm/i915: Try to reset gen2 devices. So far only found registers for i830, i845, i865 and one of those has no effect on i865! At this moment in time, attempting to reset i8xx is a little optimistic... Signed-off-by: Chris Wilson --- drivers/gpu/drm/i915/i915_drv.c | 33 +++++++++++++++++++++++++++++++++ drivers/gpu/drm/i915/i915_reg.h | 11 +++++++++++ 2 files changed, 44 insertions(+) diff --git a/drivers/gpu/drm/i915/i915_drv.c b/drivers/gpu/drm/i915/i915_drv.c index 2109537..f3243a3 100644 --- a/drivers/gpu/drm/i915/i915_drv.c +++ b/drivers/gpu/drm/i915/i915_drv.c @@ -342,6 +342,36 @@ int i915_resume(struct drm_device *dev) return 0; } +static int i8xx_do_reset(struct drm_device *dev, u8 flags) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + + if (IS_I85X(dev)) + return -ENODEV; + + I915_WRITE(D_STATE, I915_READ(D_STATE) | DSTATE_GFX_RESET_I830); + POSTING_READ(D_STATE); + + if (IS_I830(dev) || IS_845G(dev)) { + I915_WRITE(DEBUG_RESET_I830, + DEBUG_RESET_DISPLAY | + DEBUG_RESET_RENDER | + DEBUG_RESET_FULL); + POSTING_READ(DEBUG_RESET_I830); + msleep(1); + + I915_WRITE(DEBUG_RESET_I830, 0); + POSTING_READ(DEBUG_RESET_I830); + } + + msleep(1); + + I915_WRITE(D_STATE, I915_READ(D_STATE) & ~DSTATE_GFX_RESET_I830); + POSTING_READ(D_STATE); + + return 0; +} + static int i965_reset_complete(struct drm_device *dev) { u8 gdrst; @@ -410,6 +440,9 @@ int i915_reset(struct drm_device *dev, u8 flags) case 4: ret = i965_do_reset(dev, flags); break; + case 2: + ret = i8xx_do_reset(dev, flags); + break; } if (ret) { DRM_ERROR("Failed to reset chip.\n"); diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index ddbcd8c..58cfea2 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -216,6 +216,16 @@ #define PIPE_CONTROL_GLOBAL_GTT (1<<2) /* in addr dword */ #define PIPE_CONTROL_STALL_EN (1<<1) /* in addr word, Ironlake+ only */ + +/* + * Reset registers + */ +#define DEBUG_RESET_I830 0x6070 +#define DEBUG_RESET_FULL (1<<7) +#define DEBUG_RESET_RENDER (1<<8) +#define DEBUG_RESET_DISPLAY (1<<9) + + /* * Fence registers */ @@ -763,6 +773,7 @@ #define DPLLA_TEST_M_BYPASS (1 << 2) #define DPLLA_INPUT_BUFFER_ENABLE (1 << 0) #define D_STATE 0x6104 +#define DSTATE_GFX_RESET_I830 (1<<6) #define DSTATE_PLL_D3_OFF (1<<3) #define DSTATE_GFX_CLOCK_GATING (1<<1) #define DSTATE_DOT_CLOCK_GATING (1<<0) -- cgit v1.1 From 2fa772f34042cd4ddfb4ffaf5c24f0ce8c1025e9 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Fri, 1 Oct 2010 13:23:27 +0100 Subject: drm/i915: Only print 'generating error event' if we actually are Signed-off-by: Chris Wilson --- drivers/gpu/drm/i915/i915_irq.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c index aaa0f1b..64c07c2 100644 --- a/drivers/gpu/drm/i915/i915_irq.c +++ b/drivers/gpu/drm/i915/i915_irq.c @@ -396,7 +396,6 @@ static void i915_error_work_func(struct work_struct *work) char *reset_event[] = { "RESET=1", NULL }; char *reset_done_event[] = { "ERROR=0", NULL }; - DRM_DEBUG_DRIVER("generating error event\n"); kobject_uevent_env(&dev->primary->kdev.kobj, KOBJ_CHANGE, error_event); if (atomic_read(&dev_priv->mm.wedged)) { @@ -574,8 +573,10 @@ static void i915_capture_error_state(struct drm_device *dev) return; } + DRM_DEBUG_DRIVER("generating error event\n"); + error->seqno = - dev_priv->render_ring.get_seqno(dev, &dev_priv->render_ring); + dev_priv->render_ring.get_seqno(dev, &dev_priv->render_ring); error->eir = I915_READ(EIR); error->pgtbl_er = I915_READ(PGTBL_ER); error->pipeastat = I915_READ(PIPEASTAT); -- cgit v1.1 From ae681d969ac0946e09636f2bef7a126d73e1ad6b Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Fri, 1 Oct 2010 14:57:56 +0100 Subject: drm/i915: If the GPU hangs twice within 5 seconds, declare it wedged. The issue is that we may become stuck executing a long running shader and continually attempt to reset the GPU. (Or maybe we tickle some bug and need to break the vicious cycle.) So if we are detect a second hang within 5 seconds, give up trying to programme the GPU and report it wedged. Signed-off-by: Chris Wilson --- drivers/gpu/drm/i915/i915_drv.c | 15 +++++++++------ drivers/gpu/drm/i915/i915_drv.h | 2 ++ 2 files changed, 11 insertions(+), 6 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_drv.c b/drivers/gpu/drm/i915/i915_drv.c index f3243a3..c3decb2 100644 --- a/drivers/gpu/drm/i915/i915_drv.c +++ b/drivers/gpu/drm/i915/i915_drv.c @@ -383,6 +383,11 @@ static int i965_do_reset(struct drm_device *dev, u8 flags) { u8 gdrst; + /* + * Set the domains we want to reset (GRDOM/bits 2 and 3) as + * well as the reset bit (GR/bit 0). Setting the GR bit + * triggers the reset; when done, the hardware will clear it. + */ pci_read_config_byte(dev->pdev, I965_GDRST, &gdrst); pci_write_config_byte(dev->pdev, I965_GDRST, gdrst | flags | 0x1); @@ -427,13 +432,10 @@ int i915_reset(struct drm_device *dev, u8 flags) i915_gem_reset(dev); - /* - * Set the domains we want to reset (GRDOM/bits 2 and 3) as - * well as the reset bit (GR/bit 0). Setting the GR bit - * triggers the reset; when done, the hardware will clear it. - */ ret = -ENODEV; - switch (INTEL_INFO(dev)->gen) { + if (get_seconds() - dev_priv->last_gpu_reset < 5) { + DRM_ERROR("GPU hanging too fast, declaring wedged!\n"); + } else switch (INTEL_INFO(dev)->gen) { case 5: ret = ironlake_do_reset(dev, flags); break; @@ -444,6 +446,7 @@ int i915_reset(struct drm_device *dev, u8 flags) ret = i8xx_do_reset(dev, flags); break; } + dev_priv->last_gpu_reset = get_seconds(); if (ret) { DRM_ERROR("Failed to reset chip.\n"); mutex_unlock(&dev->struct_mutex); diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index d19a26af..73ad8bf 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -699,6 +699,8 @@ typedef struct drm_i915_private { struct drm_mm_node *compressed_fb; struct drm_mm_node *compressed_llb; + unsigned long last_gpu_reset; + /* list of fbdev register on this device */ struct intel_fbdev *fbdev; } drm_i915_private_t; -- cgit v1.1 From 1cdf7fef793c715d8c4998575aba3741fa4a0b01 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Sat, 2 Oct 2010 15:12:41 +0100 Subject: drm/i915: Don't mask the return code whilst relocating. The return from move_to_gtt_domain() may indicate a pending signal which needs to handled as opposed to an actual error, for instance, so report the original return value rather than forcing an EINVAL. Signed-off-by: Chris Wilson --- drivers/gpu/drm/i915/i915_gem.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index db9d36f..a78c973 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -3454,7 +3454,7 @@ i915_gem_object_pin_and_relocate(struct drm_gem_object *obj, if (ret != 0) { drm_gem_object_unreference(target_obj); i915_gem_object_unpin(obj); - return -EINVAL; + return ret; } /* Map the page containing the relocation we're going to -- cgit v1.1 From 929f49bf225b1b6cd04d0a7b9c0f7377d9131220 Mon Sep 17 00:00:00 2001 From: Julia Lawall Date: Sat, 2 Oct 2010 15:59:17 +0200 Subject: drivers/gpu/drm/i915/i915_gem.c: Add missing error handling code Extend the error handling code with operations found in other nearby error handling code A simplified version of the sematic match that finds this problem is as follows: (http://coccinelle.lip6.fr/) // @r exists@ @r@ statement S1,S2,S3; constant C1,C2,C3; @@ *if (...) {... S1 return -C1;} ... *if (...) {... when != S1 return -C2;} ... *if (...) {... S1 return -C3;} // Signed-off-by: Julia Lawall Signed-off-by: Chris Wilson Cc: stable@kernel.org --- drivers/gpu/drm/i915/i915_gem.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index bced9b2..cfe5978 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -3258,6 +3258,8 @@ i915_gem_object_pin_and_relocate(struct drm_gem_object *obj, (int) reloc->offset, reloc->read_domains, reloc->write_domain); + drm_gem_object_unreference(target_obj); + i915_gem_object_unpin(obj); return -EINVAL; } if (reloc->write_domain & I915_GEM_DOMAIN_CPU || -- cgit v1.1 From b99a9d9bb62a984bdfcb6c973dfe180bd776abbe Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Sun, 3 Oct 2010 00:33:05 -0700 Subject: drm/i915: vblank status not valid while training display port While the display port is in training mode, vblank interrupts don't occur. Because we have to wait for the display port output to turn on before starting the training sequence, enable the output in 'normal' mode so that we can tell when a vblank has occurred, then start the training sequence. Signed-off-by: Keith Packard Signed-off-by: Chris Wilson --- drivers/gpu/drm/i915/intel_dp.c | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c index 1a51ee0..9ab8708 100644 --- a/drivers/gpu/drm/i915/intel_dp.c +++ b/drivers/gpu/drm/i915/intel_dp.c @@ -1138,18 +1138,14 @@ static bool intel_dp_set_link_train(struct intel_dp *intel_dp, uint32_t dp_reg_value, uint8_t dp_train_pat, - uint8_t train_set[4], - bool first) + uint8_t train_set[4]) { struct drm_device *dev = intel_dp->base.enc.dev; struct drm_i915_private *dev_priv = dev->dev_private; - struct intel_crtc *intel_crtc = to_intel_crtc(intel_dp->base.enc.crtc); int ret; I915_WRITE(intel_dp->output_reg, dp_reg_value); POSTING_READ(intel_dp->output_reg); - if (first) - intel_wait_for_vblank(dev, intel_crtc->pipe); intel_dp_aux_native_write_1(intel_dp, DP_TRAINING_PATTERN_SET, @@ -1174,10 +1170,15 @@ intel_dp_link_train(struct intel_dp *intel_dp) uint8_t voltage; bool clock_recovery = false; bool channel_eq = false; - bool first = true; int tries; u32 reg; uint32_t DP = intel_dp->DP; + struct intel_crtc *intel_crtc = to_intel_crtc(intel_dp->base.enc.crtc); + + /* Enable output, wait for it to become active */ + I915_WRITE(intel_dp->output_reg, intel_dp->DP); + POSTING_READ(intel_dp->output_reg); + intel_wait_for_vblank(dev, intel_crtc->pipe); /* Write the link configuration data */ intel_dp_aux_native_write(intel_dp, DP_LINK_BW_SET, @@ -1210,9 +1211,8 @@ intel_dp_link_train(struct intel_dp *intel_dp) reg = DP | DP_LINK_TRAIN_PAT_1; if (!intel_dp_set_link_train(intel_dp, reg, - DP_TRAINING_PATTERN_1, train_set, first)) + DP_TRAINING_PATTERN_1, train_set)) break; - first = false; /* Set training pattern 1 */ udelay(100); @@ -1266,8 +1266,7 @@ intel_dp_link_train(struct intel_dp *intel_dp) /* channel eq pattern */ if (!intel_dp_set_link_train(intel_dp, reg, - DP_TRAINING_PATTERN_2, train_set, - false)) + DP_TRAINING_PATTERN_2, train_set)) break; udelay(400); -- cgit v1.1 From ab7ad7f6451580aa7eccc0ba62807c872088a8f9 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Sun, 3 Oct 2010 00:33:06 -0700 Subject: drm/i915: Use pipe state to tell when pipe is off Instead of waiting for the display line value to settle, we can simply wait for the pipe configuration register 'state' bit to turn off. Contrarywise, disabling the plane will not cause the display line value to stop changing, so instead we wait for the vblank interrupt bit to get set. And, we only do this when we're not about to wait for the pipe to turn off. Signed-off-by: Keith Packard Signed-off-by: Chris Wilson --- drivers/gpu/drm/i915/intel_display.c | 62 ++++++++++++++++++++++-------------- drivers/gpu/drm/i915/intel_drv.h | 1 - 2 files changed, 38 insertions(+), 25 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index b5bf51a..9792285 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -1013,8 +1013,8 @@ void intel_wait_for_vblank(struct drm_device *dev, int pipe) DRM_DEBUG_KMS("vblank wait timed out\n"); } -/** - * intel_wait_for_vblank_off - wait for vblank after disabling a pipe +/* + * intel_wait_for_pipe_off - wait for pipe to turn off * @dev: drm device * @pipe: pipe to wait for * @@ -1022,25 +1022,39 @@ void intel_wait_for_vblank(struct drm_device *dev, int pipe) * spinning on the vblank interrupt status bit, since we won't actually * see an interrupt when the pipe is disabled. * - * So this function waits for the display line value to settle (it - * usually ends up stopping at the start of the next frame). + * On Gen4 and above: + * wait for the pipe register state bit to turn off + * + * Otherwise: + * wait for the display line value to settle (it usually + * ends up stopping at the start of the next frame). + * */ -void intel_wait_for_vblank_off(struct drm_device *dev, int pipe) +static void intel_wait_for_pipe_off(struct drm_device *dev, int pipe) { struct drm_i915_private *dev_priv = dev->dev_private; - int pipedsl_reg = (pipe == 0 ? PIPEADSL : PIPEBDSL); - unsigned long timeout = jiffies + msecs_to_jiffies(100); - u32 last_line; - - /* Wait for the display line to settle */ - do { - last_line = I915_READ(pipedsl_reg) & DSL_LINEMASK; - mdelay(5); - } while (((I915_READ(pipedsl_reg) & DSL_LINEMASK) != last_line) && - time_after(timeout, jiffies)); - - if (time_after(jiffies, timeout)) - DRM_DEBUG_KMS("vblank wait timed out\n"); + + if (INTEL_INFO(dev)->gen >= 4) { + int pipeconf_reg = (pipe == 0 ? PIPEACONF : PIPEBCONF); + + /* Wait for the Pipe State to go off */ + if (wait_for((I915_READ(pipeconf_reg) & I965_PIPECONF_ACTIVE) == 0, + 100, 0)) + DRM_DEBUG_KMS("pipe_off wait timed out\n"); + } else { + u32 last_line; + int pipedsl_reg = (pipe == 0 ? PIPEADSL : PIPEBDSL); + unsigned long timeout = jiffies + msecs_to_jiffies(100); + + /* Wait for the display line to settle */ + do { + last_line = I915_READ(pipedsl_reg) & DSL_LINEMASK; + mdelay(5); + } while (((I915_READ(pipedsl_reg) & DSL_LINEMASK) != last_line) && + time_after(timeout, jiffies)); + if (time_after(jiffies, timeout)) + DRM_DEBUG_KMS("pipe_off wait timed out\n"); + } } /* Parameters have changed, update FBC info */ @@ -2328,13 +2342,13 @@ static void i9xx_crtc_dpms(struct drm_crtc *crtc, int mode) I915_READ(dspbase_reg); } - /* Wait for vblank for the disable to take effect */ - intel_wait_for_vblank_off(dev, pipe); - /* Don't disable pipe A or pipe A PLLs if needed */ if (pipeconf_reg == PIPEACONF && - (dev_priv->quirks & QUIRK_PIPEA_FORCE)) + (dev_priv->quirks & QUIRK_PIPEA_FORCE)) { + /* Wait for vblank for the disable to take effect */ + intel_wait_for_vblank(dev, pipe); goto skip_pipe_off; + } /* Next, disable display pipes */ temp = I915_READ(pipeconf_reg); @@ -2343,8 +2357,8 @@ static void i9xx_crtc_dpms(struct drm_crtc *crtc, int mode) I915_READ(pipeconf_reg); } - /* Wait for vblank for the disable to take effect. */ - intel_wait_for_vblank_off(dev, pipe); + /* Wait for the pipe to turn off */ + intel_wait_for_pipe_off(dev, pipe); temp = I915_READ(dpll_reg); if ((temp & DPLL_VCO_ENABLE) != 0) { diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index ad312ca..8828b3a 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -229,7 +229,6 @@ extern struct drm_display_mode *intel_crtc_mode_get(struct drm_device *dev, struct drm_crtc *crtc); int intel_get_pipe_from_crtc_id(struct drm_device *dev, void *data, struct drm_file *file_priv); -extern void intel_wait_for_vblank_off(struct drm_device *dev, int pipe); extern void intel_wait_for_vblank(struct drm_device *dev, int pipe); extern struct drm_crtc *intel_get_crtc_from_pipe(struct drm_device *dev, int pipe); extern struct drm_crtc *intel_get_load_detect_pipe(struct intel_encoder *intel_encoder, -- cgit v1.1 From ce9d419dbecc292cc3e06e8b1d6d123d3fa813a4 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Sun, 26 Sep 2010 20:50:05 +0100 Subject: drm/i915: Sanity check pread/pwrite Move the access control up from the fast paths, which are no longer universally taken first, up into the caller. This then duplicates some sanity checking along the slow paths, but is much simpler. Tracked as CVE-2010-2962. Reported-by: Kees Cook Signed-off-by: Chris Wilson Cc: stable@kernel.org --- drivers/gpu/drm/i915/i915_gem.c | 28 ++++++++++++++++++++-------- 1 file changed, 20 insertions(+), 8 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index cfe5978..7749e78 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -477,8 +477,15 @@ i915_gem_pread_ioctl(struct drm_device *dev, void *data, */ if (args->offset > obj->size || args->size > obj->size || args->offset + args->size > obj->size) { - drm_gem_object_unreference_unlocked(obj); - return -EINVAL; + ret = -EINVAL; + goto err; + } + + if (!access_ok(VERIFY_WRITE, + (char __user *)(uintptr_t)args->data_ptr, + args->size)) { + ret = -EFAULT; + goto err; } if (i915_gem_object_needs_bit17_swizzle(obj)) { @@ -490,8 +497,8 @@ i915_gem_pread_ioctl(struct drm_device *dev, void *data, file_priv); } +err: drm_gem_object_unreference_unlocked(obj); - return ret; } @@ -580,8 +587,6 @@ i915_gem_gtt_pwrite_fast(struct drm_device *dev, struct drm_gem_object *obj, user_data = (char __user *) (uintptr_t) args->data_ptr; remain = args->size; - if (!access_ok(VERIFY_READ, user_data, remain)) - return -EFAULT; mutex_lock(&dev->struct_mutex); @@ -940,8 +945,15 @@ i915_gem_pwrite_ioctl(struct drm_device *dev, void *data, */ if (args->offset > obj->size || args->size > obj->size || args->offset + args->size > obj->size) { - drm_gem_object_unreference_unlocked(obj); - return -EINVAL; + ret = -EINVAL; + goto err; + } + + if (!access_ok(VERIFY_READ, + (char __user *)(uintptr_t)args->data_ptr, + args->size)) { + ret = -EFAULT; + goto err; } /* We can only do the GTT pwrite on untiled buffers, as otherwise @@ -975,8 +987,8 @@ i915_gem_pwrite_ioctl(struct drm_device *dev, void *data, DRM_INFO("pwrite failed %d\n", ret); #endif +err: drm_gem_object_unreference_unlocked(obj); - return ret; } -- cgit v1.1 From 7dcd2499deab8f10011713c40bc2f309c9b65077 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Sun, 26 Sep 2010 20:21:44 +0100 Subject: drm/i915: Rephrase pwrite bounds checking to avoid any potential overflow ... and do the same for pread. Signed-off-by: Chris Wilson Cc: stable@kernel.org --- drivers/gpu/drm/i915/i915_gem.c | 16 ++++------------ 1 file changed, 4 insertions(+), 12 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index 7749e78..aa959c4a 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -471,12 +471,8 @@ i915_gem_pread_ioctl(struct drm_device *dev, void *data, return -ENOENT; obj_priv = to_intel_bo(obj); - /* Bounds check source. - * - * XXX: This could use review for overflow issues... - */ - if (args->offset > obj->size || args->size > obj->size || - args->offset + args->size > obj->size) { + /* Bounds check source. */ + if (args->offset > obj->size || args->size > obj->size - args->offset) { ret = -EINVAL; goto err; } @@ -939,12 +935,8 @@ i915_gem_pwrite_ioctl(struct drm_device *dev, void *data, return -ENOENT; obj_priv = to_intel_bo(obj); - /* Bounds check destination. - * - * XXX: This could use review for overflow issues... - */ - if (args->offset > obj->size || args->size > obj->size || - args->offset + args->size > obj->size) { + /* Bounds check destination. */ + if (args->offset > obj->size || args->size > obj->size - args->offset) { ret = -EINVAL; goto err; } -- cgit v1.1 From f87ea7613126ace98c0cb8b86f58e16a0e539375 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Sun, 3 Oct 2010 19:36:26 -0700 Subject: drm/i915: avoid struct mutex output_poll mutex lock loop on unload Cancel the output polling work proc before acquiring the struct mutex to avoid acquiring the work proc mutex with the struct mutex held. This avoids inverting the lock order seen when the work proc runs. Signed-off-by: Keith Packard Signed-off-by: Chris Wilson --- drivers/gpu/drm/i915/intel_display.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index a2e8e15..f55b560 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -6127,9 +6127,9 @@ void intel_modeset_cleanup(struct drm_device *dev) struct drm_crtc *crtc; struct intel_crtc *intel_crtc; + drm_kms_helper_poll_fini(dev); mutex_lock(&dev->struct_mutex); - drm_kms_helper_poll_fini(dev); intel_fbdev_fini(dev); list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { -- cgit v1.1 From 35b62a89b0723ca05831f2edfff6deebe1806f21 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Sun, 26 Sep 2010 20:23:38 +0100 Subject: drm/i915: Skip pread/pwrite if size to copy is 0. Signed-off-by: Chris Wilson --- drivers/gpu/drm/i915/i915_gem.c | 20 +++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index dba8202..29e97c0 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -576,7 +576,7 @@ i915_gem_pread_ioctl(struct drm_device *dev, void *data, struct drm_i915_gem_pread *args = data; struct drm_gem_object *obj; struct drm_i915_gem_object *obj_priv; - int ret; + int ret = 0; obj = drm_gem_object_lookup(dev, file_priv, args->handle); if (obj == NULL) @@ -586,14 +586,17 @@ i915_gem_pread_ioctl(struct drm_device *dev, void *data, /* Bounds check source. */ if (args->offset > obj->size || args->size > obj->size - args->offset) { ret = -EINVAL; - goto err; + goto out; } + if (args->size == 0) + goto out; + if (!access_ok(VERIFY_WRITE, (char __user *)(uintptr_t)args->data_ptr, args->size)) { ret = -EFAULT; - goto err; + goto out; } if (i915_gem_object_needs_bit17_swizzle(obj)) { @@ -605,7 +608,7 @@ i915_gem_pread_ioctl(struct drm_device *dev, void *data, file_priv); } -err: +out: drm_gem_object_unreference_unlocked(obj); return ret; } @@ -1059,14 +1062,17 @@ i915_gem_pwrite_ioctl(struct drm_device *dev, void *data, /* Bounds check destination. */ if (args->offset > obj->size || args->size > obj->size - args->offset) { ret = -EINVAL; - goto err; + goto out; } + if (args->size == 0) + goto out; + if (!access_ok(VERIFY_READ, (char __user *)(uintptr_t)args->data_ptr, args->size)) { ret = -EFAULT; - goto err; + goto out; } /* We can only do the GTT pwrite on untiled buffers, as otherwise @@ -1100,7 +1106,7 @@ i915_gem_pwrite_ioctl(struct drm_device *dev, void *data, DRM_INFO("pwrite failed %d\n", ret); #endif -err: +out: drm_gem_object_unreference_unlocked(obj); return ret; } -- cgit v1.1 From 2c6be944111a873ce96865f1a6033056bdf0d0e2 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Sun, 3 Oct 2010 13:33:49 -0700 Subject: drm/i915: mark display port DPMS state as 'ON' when enabling output The display port DPMS state is tracked internally in the display port driver so that when a hotplug event comes along, the driver can know whether to try retraining the link. This doesn't work well if the driver never sets the DPMS state to ON when the output is enabled. Signed-off-by: Keith Packard Signed-off-by: Chris Wilson --- drivers/gpu/drm/i915/intel_dp.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c index 9e8fe12..152d945 100644 --- a/drivers/gpu/drm/i915/intel_dp.c +++ b/drivers/gpu/drm/i915/intel_dp.c @@ -933,6 +933,7 @@ static void intel_dp_commit(struct drm_encoder *encoder) if (IS_eDP(intel_dp) || IS_PCH_eDP(intel_dp)) ironlake_edp_backlight_on(dev); + intel_dp->dpms_mode = DRM_MODE_DPMS_ON; } static void -- cgit v1.1 From 7b4f3990a22fbe800945f12001bc30db374d0af5 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Mon, 4 Oct 2010 15:33:04 +0100 Subject: drm/i915: Avoid circular locking from intel_fbdev_fini() lockdep spots that the fb_info->lock takes the dev->struct_mutex during init (due to the device probing) and so we can not hold dev->struct_mutex when unregistering the framebuffer. Simply reverse the order of initialisation during cleanup and so do the intel_fbdev_fini() before the intel_modeset_cleanup. Signed-off-by: Chris Wilson --- drivers/gpu/drm/i915/i915_dma.c | 1 + drivers/gpu/drm/i915/intel_display.c | 2 -- drivers/gpu/drm/i915/intel_fb.c | 8 +++----- 3 files changed, 4 insertions(+), 7 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_dma.c b/drivers/gpu/drm/i915/i915_dma.c index df86d04..726c373 100644 --- a/drivers/gpu/drm/i915/i915_dma.c +++ b/drivers/gpu/drm/i915/i915_dma.c @@ -2106,6 +2106,7 @@ int i915_driver_unload(struct drm_device *dev) acpi_video_unregister(); if (drm_core_check_feature(dev, DRIVER_MODESET)) { + intel_fbdev_fini(dev); intel_modeset_cleanup(dev); /* diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index f55b560..69c54c5 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -6130,8 +6130,6 @@ void intel_modeset_cleanup(struct drm_device *dev) drm_kms_helper_poll_fini(dev); mutex_lock(&dev->struct_mutex); - intel_fbdev_fini(dev); - list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { /* Skip inactive CRTCs */ if (!crtc->fb) diff --git a/drivers/gpu/drm/i915/intel_fb.c b/drivers/gpu/drm/i915/intel_fb.c index 7af4acc..7dc50ac 100644 --- a/drivers/gpu/drm/i915/intel_fb.c +++ b/drivers/gpu/drm/i915/intel_fb.c @@ -206,8 +206,8 @@ static struct drm_fb_helper_funcs intel_fb_helper_funcs = { .fb_probe = intel_fb_find_or_create_single, }; -static int intel_fbdev_destroy(struct drm_device *dev, - struct intel_fbdev *ifbdev) +static void intel_fbdev_destroy(struct drm_device *dev, + struct intel_fbdev *ifbdev) { struct fb_info *info; struct intel_framebuffer *ifb = &ifbdev->ifb; @@ -225,9 +225,7 @@ static int intel_fbdev_destroy(struct drm_device *dev, drm_framebuffer_cleanup(&ifb->base); if (ifb->obj) - drm_gem_object_unreference(ifb->obj); - - return 0; + drm_gem_object_unreference_unlocked(ifb->obj); } int intel_fbdev_init(struct drm_device *dev) -- cgit v1.1