Merge tag 'amdkfd-fixes-2014-12-23' of git://people.freedesktop.org/~gabbayo/linux...
authorDave Airlie <airlied@redhat.com>
Wed, 24 Dec 2014 02:59:08 +0000 (12:59 +1000)
committerDave Airlie <airlied@redhat.com>
Wed, 24 Dec 2014 02:59:08 +0000 (12:59 +1000)
- Display MEC fw version in topology. Without this, the HSA userspace
  stack is broken.

- Init apertures information only once per process

* tag 'amdkfd-fixes-2014-12-23' of git://people.freedesktop.org/~gabbayo/linux:
  amdkfd: init aperture once per process
  amdkfd: Display MEC fw version in topology node
  drm/radeon: Add implementation of get_fw_version
  drm/amd: Add get_fw_version to kfd-->kgd interface

33 files changed:
drivers/char/agp/ali-agp.c
drivers/char/agp/amd64-agp.c
drivers/char/agp/ati-agp.c
drivers/char/agp/backend.c
drivers/char/agp/intel-agp.c
drivers/char/agp/intel-gtt.c
drivers/char/agp/nvidia-agp.c
drivers/char/agp/via-agp.c
drivers/gpu/drm/drm_atomic_helper.c
drivers/gpu/drm/drm_irq.c
drivers/gpu/drm/i915/i915_drv.c
drivers/gpu/drm/i915/i915_gem_context.c
drivers/gpu/drm/i915/i915_irq.c
drivers/gpu/drm/i915/i915_reg.h
drivers/gpu/drm/i915/intel_pm.c
drivers/gpu/drm/i915/intel_ringbuffer.c
drivers/gpu/drm/msm/adreno/adreno_gpu.c
drivers/gpu/drm/msm/hdmi/hdmi_connector.c
drivers/gpu/drm/msm/mdp/mdp4/mdp4_crtc.c
drivers/gpu/drm/msm/mdp/mdp5/mdp5_crtc.c
drivers/gpu/drm/msm/mdp/mdp5/mdp5_kms.c
drivers/gpu/drm/msm/mdp/mdp_kms.c
drivers/gpu/drm/msm/mdp/mdp_kms.h
drivers/gpu/drm/msm/msm_atomic.c
drivers/gpu/drm/msm/msm_drv.c
drivers/gpu/drm/msm/msm_drv.h
drivers/gpu/drm/msm/msm_fbdev.c
drivers/gpu/drm/msm/msm_gem.c
drivers/gpu/drm/nouveau/nouveau_ttm.c
drivers/gpu/drm/tegra/dc.c
drivers/gpu/drm/tegra/drm.c
drivers/gpu/drm/tegra/gem.c
include/drm/drmP.h

index 19db036676505519fb19538299afe2f5c84dd42a..dcbbb4ea3cc1d7040a847799fad2415e44a24e08 100644 (file)
@@ -417,6 +417,6 @@ static void __exit agp_ali_cleanup(void)
 module_init(agp_ali_init);
 module_exit(agp_ali_cleanup);
 
-MODULE_AUTHOR("Dave Jones <davej@redhat.com>");
+MODULE_AUTHOR("Dave Jones");
 MODULE_LICENSE("GPL and additional rights");
 
index 3b47ed0310e1fcbb73eda184cb810c1b3ea2889b..0ef350010766355c933ebe7e48ce41a78656b0ac 100644 (file)
@@ -813,6 +813,6 @@ static void __exit agp_amd64_cleanup(void)
 module_init(agp_amd64_mod_init);
 module_exit(agp_amd64_cleanup);
 
-MODULE_AUTHOR("Dave Jones <davej@redhat.com>, Andi Kleen");
+MODULE_AUTHOR("Dave Jones, Andi Kleen");
 module_param(agp_try_unsupported, bool, 0);
 MODULE_LICENSE("GPL");
index 18a7a6baa304eadfc3968a640f97ac3da590b106..75a9786a77e6307711a74bcde8f4dd7fee8fcae0 100644 (file)
@@ -579,6 +579,6 @@ static void __exit agp_ati_cleanup(void)
 module_init(agp_ati_init);
 module_exit(agp_ati_cleanup);
 
-MODULE_AUTHOR("Dave Jones <davej@redhat.com>");
+MODULE_AUTHOR("Dave Jones");
 MODULE_LICENSE("GPL and additional rights");
 
index 317c28ce8328bb310c892c8bab4aca60cbbbc4f5..38ffb281df97c71eee3dc8980a98e19df3ca24d3 100644 (file)
@@ -356,7 +356,7 @@ static __init int agp_setup(char *s)
 __setup("agp=", agp_setup);
 #endif
 
-MODULE_AUTHOR("Dave Jones <davej@redhat.com>");
+MODULE_AUTHOR("Dave Jones, Jeff Hartmann");
 MODULE_DESCRIPTION("AGP GART driver");
 MODULE_LICENSE("GPL and additional rights");
 MODULE_ALIAS_MISCDEV(AGPGART_MINOR);
index f9b9ca5d31b7946c3b1407ef692db1c2c149c628..0a21daed5b6251edd8136bc014d073ab734a2a0a 100644 (file)
@@ -920,5 +920,5 @@ static void __exit agp_intel_cleanup(void)
 module_init(agp_intel_init);
 module_exit(agp_intel_cleanup);
 
-MODULE_AUTHOR("Dave Jones <davej@redhat.com>");
+MODULE_AUTHOR("Dave Jones, Various @Intel");
 MODULE_LICENSE("GPL and additional rights");
index f3334829e55a3e6ac393a348c6da0e7aef159709..92aa43fa8d70205e621cc3f3fe03e8bbcd94a42f 100644 (file)
@@ -1438,5 +1438,5 @@ void intel_gmch_remove(void)
 }
 EXPORT_SYMBOL(intel_gmch_remove);
 
-MODULE_AUTHOR("Dave Jones <davej@redhat.com>");
+MODULE_AUTHOR("Dave Jones, Various @Intel");
 MODULE_LICENSE("GPL and additional rights");
index a1861b75eb31a9fe433e32105ef623092741052e..6c8d39cb566e32ea4ac14c818f3bd16962823097 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * Nvidia AGPGART routines.
  * Based upon a 2.4 agpgart diff by the folks from NVIDIA, and hacked up
- * to work in 2.5 by Dave Jones <davej@redhat.com>
+ * to work in 2.5 by Dave Jones.
  */
 
 #include <linux/module.h>
index 228f20cddc056244711805b20c44d168a4d94493..a4961d35e94046de34896c492e032b9c5e72c1ae 100644 (file)
@@ -595,4 +595,4 @@ module_init(agp_via_init);
 module_exit(agp_via_cleanup);
 
 MODULE_LICENSE("GPL");
-MODULE_AUTHOR("Dave Jones <davej@redhat.com>");
+MODULE_AUTHOR("Dave Jones");
index 4a78a773151ce71f464d36cc4d1d6d887eea1619..bbdbe4721573a92667fe3989bbc1e0be8123bc2b 100644 (file)
@@ -61,7 +61,7 @@ drm_atomic_helper_plane_changed(struct drm_atomic_state *state,
        struct drm_crtc_state *crtc_state;
 
        if (plane->state->crtc) {
-               crtc_state = state->crtc_states[drm_crtc_index(plane->crtc)];
+               crtc_state = state->crtc_states[drm_crtc_index(plane->state->crtc)];
 
                if (WARN_ON(!crtc_state))
                        return;
index f5a5f18efa5bf230d810d8c031bb30cfddd0390a..4d79dad9d44fad0ac48b2b81177ffda8430b390b 100644 (file)
@@ -830,6 +830,8 @@ drm_get_last_vbltimestamp(struct drm_device *dev, int crtc,
  * vblank events since the system was booted, including lost events due to
  * modesetting activity.
  *
+ * This is the legacy version of drm_crtc_vblank_count().
+ *
  * Returns:
  * The software vblank counter.
  */
@@ -843,6 +845,25 @@ u32 drm_vblank_count(struct drm_device *dev, int crtc)
 }
 EXPORT_SYMBOL(drm_vblank_count);
 
+/**
+ * drm_crtc_vblank_count - retrieve "cooked" vblank counter value
+ * @crtc: which counter to retrieve
+ *
+ * Fetches the "cooked" vblank count value that represents the number of
+ * vblank events since the system was booted, including lost events due to
+ * modesetting activity.
+ *
+ * This is the native KMS version of drm_vblank_count().
+ *
+ * Returns:
+ * The software vblank counter.
+ */
+u32 drm_crtc_vblank_count(struct drm_crtc *crtc)
+{
+       return drm_vblank_count(crtc->dev, drm_crtc_index(crtc));
+}
+EXPORT_SYMBOL(drm_crtc_vblank_count);
+
 /**
  * drm_vblank_count_and_time - retrieve "cooked" vblank counter value
  * and the system timestamp corresponding to that vblank counter value.
@@ -904,6 +925,8 @@ static void send_vblank_event(struct drm_device *dev,
  *
  * Updates sequence # and timestamp on event, and sends it to userspace.
  * Caller must hold event lock.
+ *
+ * This is the legacy version of drm_crtc_send_vblank_event().
  */
 void drm_send_vblank_event(struct drm_device *dev, int crtc,
                struct drm_pending_vblank_event *e)
@@ -922,6 +945,23 @@ void drm_send_vblank_event(struct drm_device *dev, int crtc,
 }
 EXPORT_SYMBOL(drm_send_vblank_event);
 
+/**
+ * drm_crtc_send_vblank_event - helper to send vblank event after pageflip
+ * @crtc: the source CRTC of the vblank event
+ * @e: the event to send
+ *
+ * Updates sequence # and timestamp on event, and sends it to userspace.
+ * Caller must hold event lock.
+ *
+ * This is the native KMS version of drm_send_vblank_event().
+ */
+void drm_crtc_send_vblank_event(struct drm_crtc *crtc,
+                               struct drm_pending_vblank_event *e)
+{
+       drm_send_vblank_event(crtc->dev, drm_crtc_index(crtc), e);
+}
+EXPORT_SYMBOL(drm_crtc_send_vblank_event);
+
 /**
  * drm_vblank_enable - enable the vblank interrupt on a CRTC
  * @dev: DRM device
@@ -1594,6 +1634,8 @@ static void drm_handle_vblank_events(struct drm_device *dev, int crtc)
  *
  * Drivers should call this routine in their vblank interrupt handlers to
  * update the vblank counter and send any signals that may be pending.
+ *
+ * This is the legacy version of drm_crtc_handle_vblank().
  */
 bool drm_handle_vblank(struct drm_device *dev, int crtc)
 {
@@ -1670,3 +1712,21 @@ bool drm_handle_vblank(struct drm_device *dev, int crtc)
        return true;
 }
 EXPORT_SYMBOL(drm_handle_vblank);
+
+/**
+ * drm_crtc_handle_vblank - handle a vblank event
+ * @crtc: where this event occurred
+ *
+ * Drivers should call this routine in their vblank interrupt handlers to
+ * update the vblank counter and send any signals that may be pending.
+ *
+ * This is the native KMS version of drm_handle_vblank().
+ *
+ * Returns:
+ * True if the event was successfully handled, false on failure.
+ */
+bool drm_crtc_handle_vblank(struct drm_crtc *crtc)
+{
+       return drm_handle_vblank(crtc->dev, drm_crtc_index(crtc));
+}
+EXPORT_SYMBOL(drm_crtc_handle_vblank);
index f990ab4c3efbfbe1f91f15cc89eda8b5eb0fa64d..fc8cfddbf232ea4cd20e49d20853bd42ddb5ca48 100644 (file)
@@ -811,6 +811,8 @@ int i915_reset(struct drm_device *dev)
        if (!i915.reset)
                return 0;
 
+       intel_reset_gt_powersave(dev);
+
        mutex_lock(&dev->struct_mutex);
 
        i915_gem_reset(dev);
@@ -880,7 +882,7 @@ int i915_reset(struct drm_device *dev)
                 * of re-init after reset.
                 */
                if (INTEL_INFO(dev)->gen > 5)
-                       intel_reset_gt_powersave(dev);
+                       intel_enable_gt_powersave(dev);
        } else {
                mutex_unlock(&dev->struct_mutex);
        }
index d17ff435f2767fa31c51ed08ef5e3130aa4dddbd..d011ec82ef1ebfbb37b3c903f9d77b7e503a30f0 100644 (file)
@@ -473,7 +473,12 @@ mi_set_context(struct intel_engine_cs *ring,
               u32 hw_flags)
 {
        u32 flags = hw_flags | MI_MM_SPACE_GTT;
-       int ret;
+       const int num_rings =
+               /* Use an extended w/a on ivb+ if signalling from other rings */
+               i915_semaphore_is_enabled(ring->dev) ?
+               hweight32(INTEL_INFO(ring->dev)->ring_mask) - 1 :
+               0;
+       int len, i, ret;
 
        /* w/a: If Flush TLB Invalidation Mode is enabled, driver must do a TLB
         * invalidation prior to MI_SET_CONTEXT. On GEN6 we don't set the value
@@ -490,15 +495,31 @@ mi_set_context(struct intel_engine_cs *ring,
        if (!IS_HASWELL(ring->dev) && INTEL_INFO(ring->dev)->gen < 8)
                flags |= (MI_SAVE_EXT_STATE_EN | MI_RESTORE_EXT_STATE_EN);
 
-       ret = intel_ring_begin(ring, 6);
+
+       len = 4;
+       if (INTEL_INFO(ring->dev)->gen >= 7)
+               len += 2 + (num_rings ? 4*num_rings + 2 : 0);
+
+       ret = intel_ring_begin(ring, len);
        if (ret)
                return ret;
 
        /* WaProgramMiArbOnOffAroundMiSetContext:ivb,vlv,hsw,bdw,chv */
-       if (INTEL_INFO(ring->dev)->gen >= 7)
+       if (INTEL_INFO(ring->dev)->gen >= 7) {
                intel_ring_emit(ring, MI_ARB_ON_OFF | MI_ARB_DISABLE);
-       else
-               intel_ring_emit(ring, MI_NOOP);
+               if (num_rings) {
+                       struct intel_engine_cs *signaller;
+
+                       intel_ring_emit(ring, MI_LOAD_REGISTER_IMM(num_rings));
+                       for_each_ring(signaller, to_i915(ring->dev), i) {
+                               if (signaller == ring)
+                                       continue;
+
+                               intel_ring_emit(ring, RING_PSMI_CTL(signaller->mmio_base));
+                               intel_ring_emit(ring, _MASKED_BIT_ENABLE(GEN6_PSMI_SLEEP_MSG_DISABLE));
+                       }
+               }
+       }
 
        intel_ring_emit(ring, MI_NOOP);
        intel_ring_emit(ring, MI_SET_CONTEXT);
@@ -510,10 +531,21 @@ mi_set_context(struct intel_engine_cs *ring,
         */
        intel_ring_emit(ring, MI_NOOP);
 
-       if (INTEL_INFO(ring->dev)->gen >= 7)
+       if (INTEL_INFO(ring->dev)->gen >= 7) {
+               if (num_rings) {
+                       struct intel_engine_cs *signaller;
+
+                       intel_ring_emit(ring, MI_LOAD_REGISTER_IMM(num_rings));
+                       for_each_ring(signaller, to_i915(ring->dev), i) {
+                               if (signaller == ring)
+                                       continue;
+
+                               intel_ring_emit(ring, RING_PSMI_CTL(signaller->mmio_base));
+                               intel_ring_emit(ring, _MASKED_BIT_DISABLE(GEN6_PSMI_SLEEP_MSG_DISABLE));
+                       }
+               }
                intel_ring_emit(ring, MI_ARB_ON_OFF | MI_ARB_ENABLE);
-       else
-               intel_ring_emit(ring, MI_NOOP);
+       }
 
        intel_ring_advance(ring);
 
index 981834b0f9b6309b4f09911c4406a58fadbe0287..996c2931c49945d86a595c6f38104c475fc32f1b 100644 (file)
@@ -281,10 +281,14 @@ void gen6_enable_rps_interrupts(struct drm_device *dev)
        struct drm_i915_private *dev_priv = dev->dev_private;
 
        spin_lock_irq(&dev_priv->irq_lock);
+
        WARN_ON(dev_priv->rps.pm_iir);
        WARN_ON(I915_READ(gen6_pm_iir(dev_priv)) & dev_priv->pm_rps_events);
        dev_priv->rps.interrupts_enabled = true;
+       I915_WRITE(gen6_pm_ier(dev_priv), I915_READ(gen6_pm_ier(dev_priv)) |
+                               dev_priv->pm_rps_events);
        gen6_enable_pm_irq(dev_priv, dev_priv->pm_rps_events);
+
        spin_unlock_irq(&dev_priv->irq_lock);
 }
 
@@ -3307,8 +3311,10 @@ static void gen5_gt_irq_postinstall(struct drm_device *dev)
        GEN5_IRQ_INIT(GT, dev_priv->gt_irq_mask, gt_irqs);
 
        if (INTEL_INFO(dev)->gen >= 6) {
-               pm_irqs |= dev_priv->pm_rps_events;
-
+               /*
+                * RPS interrupts will get enabled/disabled on demand when RPS
+                * itself is enabled/disabled.
+                */
                if (HAS_VEBOX(dev))
                        pm_irqs |= PM_VEBOX_USER_INTERRUPT;
 
@@ -3520,7 +3526,11 @@ static void gen8_gt_irq_postinstall(struct drm_i915_private *dev_priv)
        dev_priv->pm_irq_mask = 0xffffffff;
        GEN8_IRQ_INIT_NDX(GT, 0, ~gt_interrupts[0], gt_interrupts[0]);
        GEN8_IRQ_INIT_NDX(GT, 1, ~gt_interrupts[1], gt_interrupts[1]);
-       GEN8_IRQ_INIT_NDX(GT, 2, dev_priv->pm_irq_mask, dev_priv->pm_rps_events);
+       /*
+        * RPS interrupts will get enabled/disabled on demand when RPS itself
+        * is enabled/disabled.
+        */
+       GEN8_IRQ_INIT_NDX(GT, 2, dev_priv->pm_irq_mask, 0);
        GEN8_IRQ_INIT_NDX(GT, 3, ~gt_interrupts[3], gt_interrupts[3]);
 }
 
@@ -3609,7 +3619,7 @@ static void vlv_display_irq_uninstall(struct drm_i915_private *dev_priv)
 
        vlv_display_irq_reset(dev_priv);
 
-       dev_priv->irq_mask = 0;
+       dev_priv->irq_mask = ~0;
 }
 
 static void valleyview_irq_uninstall(struct drm_device *dev)
index eefdc238f70bd691d584f6d32b5d055f8d1546a5..172de3b3433b20b57d7e57f31ad63d3daa09bba3 100644 (file)
 #define   PIPE_CONTROL_STORE_DATA_INDEX                        (1<<21)
 #define   PIPE_CONTROL_CS_STALL                                (1<<20)
 #define   PIPE_CONTROL_TLB_INVALIDATE                  (1<<18)
+#define   PIPE_CONTROL_MEDIA_STATE_CLEAR               (1<<16)
 #define   PIPE_CONTROL_QW_WRITE                                (1<<14)
 #define   PIPE_CONTROL_POST_SYNC_OP_MASK                (3<<14)
 #define   PIPE_CONTROL_DEPTH_STALL                     (1<<13)
@@ -1128,6 +1129,7 @@ enum punit_power_well {
 #define GEN6_VERSYNC   (RING_SYNC_1(VEBOX_RING_BASE))
 #define GEN6_VEVSYNC   (RING_SYNC_2(VEBOX_RING_BASE))
 #define GEN6_NOSYNC 0
+#define RING_PSMI_CTL(base)    ((base)+0x50)
 #define RING_MAX_IDLE(base)    ((base)+0x54)
 #define RING_HWS_PGA(base)     ((base)+0x80)
 #define RING_HWS_PGA_GEN6(base)        ((base)+0x2080)
@@ -1458,6 +1460,7 @@ enum punit_power_well {
 #define   GEN6_BLITTER_FBC_NOTIFY                      (1<<3)
 
 #define GEN6_RC_SLEEP_PSMI_CONTROL     0x2050
+#define   GEN6_PSMI_SLEEP_MSG_DISABLE  (1 << 0)
 #define   GEN8_RC_SEMA_IDLE_MSG_DISABLE        (1 << 12)
 #define   GEN8_FF_DOP_CLOCK_GATE_DISABLE       (1<<10)
 
index 1f4b56e273c811a7c33149e927985b3f973ac4b3..964b28e3c6303e5db6ecd5458c42b90b27cdd11f 100644 (file)
@@ -6191,6 +6191,20 @@ void intel_cleanup_gt_powersave(struct drm_device *dev)
                valleyview_cleanup_gt_powersave(dev);
 }
 
+static void gen6_suspend_rps(struct drm_device *dev)
+{
+       struct drm_i915_private *dev_priv = dev->dev_private;
+
+       flush_delayed_work(&dev_priv->rps.delayed_resume_work);
+
+       /*
+        * TODO: disable RPS interrupts on GEN9+ too once RPS support
+        * is added for it.
+        */
+       if (INTEL_INFO(dev)->gen < 9)
+               gen6_disable_rps_interrupts(dev);
+}
+
 /**
  * intel_suspend_gt_powersave - suspend PM work and helper threads
  * @dev: drm device
@@ -6206,14 +6220,7 @@ void intel_suspend_gt_powersave(struct drm_device *dev)
        if (INTEL_INFO(dev)->gen < 6)
                return;
 
-       flush_delayed_work(&dev_priv->rps.delayed_resume_work);
-
-       /*
-        * TODO: disable RPS interrupts on GEN9+ too once RPS support
-        * is added for it.
-        */
-       if (INTEL_INFO(dev)->gen < 9)
-               gen6_disable_rps_interrupts(dev);
+       gen6_suspend_rps(dev);
 
        /* Force GPU to min freq during suspend */
        gen6_rps_idle(dev_priv);
@@ -6316,8 +6323,11 @@ void intel_reset_gt_powersave(struct drm_device *dev)
 {
        struct drm_i915_private *dev_priv = dev->dev_private;
 
+       if (INTEL_INFO(dev)->gen < 6)
+               return;
+
+       gen6_suspend_rps(dev);
        dev_priv->rps.enabled = false;
-       intel_enable_gt_powersave(dev);
 }
 
 static void ibx_init_clock_gating(struct drm_device *dev)
index 9f445e9a75d1a1788669ab2969a2d769cf7d204e..c7bc93d28d84ec4356c0c5f5c4e4cd67296df709 100644 (file)
@@ -362,12 +362,15 @@ gen7_render_ring_flush(struct intel_engine_cs *ring,
                flags |= PIPE_CONTROL_VF_CACHE_INVALIDATE;
                flags |= PIPE_CONTROL_CONST_CACHE_INVALIDATE;
                flags |= PIPE_CONTROL_STATE_CACHE_INVALIDATE;
+               flags |= PIPE_CONTROL_MEDIA_STATE_CLEAR;
                /*
                 * TLB invalidate requires a post-sync write.
                 */
                flags |= PIPE_CONTROL_QW_WRITE;
                flags |= PIPE_CONTROL_GLOBAL_GTT_IVB;
 
+               flags |= PIPE_CONTROL_STALL_AT_SCOREBOARD;
+
                /* Workaround: we must issue a pipe_control with CS-stall bit
                 * set before a pipe_control command that has the state cache
                 * invalidate bit set. */
index aa873048308b8e6e3e431152963aed5b04c13f02..94a5bee69fe724c94542bc5181e4309e78b78300 100644 (file)
@@ -386,9 +386,7 @@ void adreno_gpu_cleanup(struct adreno_gpu *gpu)
                        msm_gem_put_iova(gpu->memptrs_bo, gpu->base.id);
                drm_gem_object_unreference(gpu->memptrs_bo);
        }
-       if (gpu->pm4)
-               release_firmware(gpu->pm4);
-       if (gpu->pfp)
-               release_firmware(gpu->pfp);
+       release_firmware(gpu->pm4);
+       release_firmware(gpu->pfp);
        msm_gpu_cleanup(&gpu->base);
 }
index fbebb0405d76d7df217c1772a26cc43e78578b29..b4e70e0e3cfa603b1ee8bbf393dd07402c96fbbb 100644 (file)
@@ -141,6 +141,15 @@ static int hpd_enable(struct hdmi_connector *hdmi_connector)
        uint32_t hpd_ctrl;
        int i, ret;
 
+       for (i = 0; i < config->hpd_reg_cnt; i++) {
+               ret = regulator_enable(hdmi->hpd_regs[i]);
+               if (ret) {
+                       dev_err(dev->dev, "failed to enable hpd regulator: %s (%d)\n",
+                                       config->hpd_reg_names[i], ret);
+                       goto fail;
+               }
+       }
+
        ret = gpio_config(hdmi, true);
        if (ret) {
                dev_err(dev->dev, "failed to configure GPIOs: %d\n", ret);
@@ -164,15 +173,6 @@ static int hpd_enable(struct hdmi_connector *hdmi_connector)
                }
        }
 
-       for (i = 0; i < config->hpd_reg_cnt; i++) {
-               ret = regulator_enable(hdmi->hpd_regs[i]);
-               if (ret) {
-                       dev_err(dev->dev, "failed to enable hpd regulator: %s (%d)\n",
-                                       config->hpd_reg_names[i], ret);
-                       goto fail;
-               }
-       }
-
        hdmi_set_mode(hdmi, false);
        phy->funcs->reset(phy);
        hdmi_set_mode(hdmi, true);
@@ -200,7 +200,7 @@ fail:
        return ret;
 }
 
-static int hdp_disable(struct hdmi_connector *hdmi_connector)
+static void hdp_disable(struct hdmi_connector *hdmi_connector)
 {
        struct hdmi *hdmi = hdmi_connector->hdmi;
        const struct hdmi_platform_config *config = hdmi->config;
@@ -212,28 +212,19 @@ static int hdp_disable(struct hdmi_connector *hdmi_connector)
 
        hdmi_set_mode(hdmi, false);
 
-       for (i = 0; i < config->hpd_reg_cnt; i++) {
-               ret = regulator_disable(hdmi->hpd_regs[i]);
-               if (ret) {
-                       dev_err(dev->dev, "failed to disable hpd regulator: %s (%d)\n",
-                                       config->hpd_reg_names[i], ret);
-                       goto fail;
-               }
-       }
-
        for (i = 0; i < config->hpd_clk_cnt; i++)
                clk_disable_unprepare(hdmi->hpd_clks[i]);
 
        ret = gpio_config(hdmi, false);
-       if (ret) {
-               dev_err(dev->dev, "failed to unconfigure GPIOs: %d\n", ret);
-               goto fail;
-       }
-
-       return 0;
+       if (ret)
+               dev_warn(dev->dev, "failed to unconfigure GPIOs: %d\n", ret);
 
-fail:
-       return ret;
+       for (i = 0; i < config->hpd_reg_cnt; i++) {
+               ret = regulator_disable(hdmi->hpd_regs[i]);
+               if (ret)
+                       dev_warn(dev->dev, "failed to disable hpd regulator: %s (%d)\n",
+                                       config->hpd_reg_names[i], ret);
+       }
 }
 
 static void
@@ -260,11 +251,11 @@ void hdmi_connector_irq(struct drm_connector *connector)
                        (hpd_int_status & HDMI_HPD_INT_STATUS_INT)) {
                bool detected = !!(hpd_int_status & HDMI_HPD_INT_STATUS_CABLE_DETECTED);
 
-               DBG("status=%04x, ctrl=%04x", hpd_int_status, hpd_int_ctrl);
-
-               /* ack the irq: */
+               /* ack & disable (temporarily) HPD events: */
                hdmi_write(hdmi, REG_HDMI_HPD_INT_CTRL,
-                               hpd_int_ctrl | HDMI_HPD_INT_CTRL_INT_ACK);
+                       HDMI_HPD_INT_CTRL_INT_ACK);
+
+               DBG("status=%04x, ctrl=%04x", hpd_int_status, hpd_int_ctrl);
 
                /* detect disconnect if we are connected or visa versa: */
                hpd_int_ctrl = HDMI_HPD_INT_CTRL_INT_EN;
index a7672e100d8b5bd5f4ac4b782a3b1d0a38197a79..3449213f1e76424f7794754f3009de631b9bd00b 100644 (file)
@@ -331,17 +331,8 @@ static int mdp4_crtc_atomic_check(struct drm_crtc *crtc,
                struct drm_crtc_state *state)
 {
        struct mdp4_crtc *mdp4_crtc = to_mdp4_crtc(crtc);
-       struct drm_device *dev = crtc->dev;
-
        DBG("%s: check", mdp4_crtc->name);
-
-       if (mdp4_crtc->event) {
-               dev_err(dev->dev, "already pending flip!\n");
-               return -EBUSY;
-       }
-
        // TODO anything else to check?
-
        return 0;
 }
 
@@ -357,7 +348,7 @@ static void mdp4_crtc_atomic_flush(struct drm_crtc *crtc)
        struct drm_device *dev = crtc->dev;
        unsigned long flags;
 
-       DBG("%s: flush", mdp4_crtc->name);
+       DBG("%s: event: %p", mdp4_crtc->name, crtc->state->event);
 
        WARN_ON(mdp4_crtc->event);
 
index 0e9a2e3a82d76e1e104fd1e136d8924755706586..f021f960a8a27f7d002fd7be8a01edb722e7323a 100644 (file)
@@ -303,11 +303,6 @@ static int mdp5_crtc_atomic_check(struct drm_crtc *crtc,
 
        DBG("%s: check", mdp5_crtc->name);
 
-       if (mdp5_crtc->event) {
-               dev_err(dev->dev, "already pending flip!\n");
-               return -EBUSY;
-       }
-
        /* request a free CTL, if none is already allocated for this CRTC */
        if (state->enable && !mdp5_crtc->ctl) {
                mdp5_crtc->ctl = mdp5_ctlm_request(mdp5_kms->ctlm, crtc);
@@ -364,7 +359,7 @@ static void mdp5_crtc_atomic_flush(struct drm_crtc *crtc)
        struct drm_device *dev = crtc->dev;
        unsigned long flags;
 
-       DBG("%s: flush", mdp5_crtc->name);
+       DBG("%s: event: %p", mdp5_crtc->name, crtc->state->event);
 
        WARN_ON(mdp5_crtc->event);
 
@@ -460,10 +455,7 @@ void mdp5_crtc_set_intf(struct drm_crtc *crtc, int intf,
        /* now that we know what irq's we want: */
        mdp5_crtc->err.irqmask = intf2err(intf);
        mdp5_crtc->vblank.irqmask = intf2vblank(intf);
-
-       /* when called from modeset_init(), skip the rest until later: */
-       if (!mdp5_kms)
-               return;
+       mdp_irq_update(&mdp5_kms->base);
 
        spin_lock_irqsave(&mdp5_kms->resource_lock, flags);
        intf_sel = mdp5_read(mdp5_kms, REG_MDP5_DISP_INTF_SEL);
index a11f1b80c488567d44755ad68eadc4d15dc61375..9f01a4f21af2fa969a58c0dc5e8e74a7346e227d 100644 (file)
@@ -216,17 +216,7 @@ static int modeset_init(struct mdp5_kms *mdp5_kms)
                goto fail;
        }
 
-       /* NOTE: the vsync and error irq's are actually associated with
-        * the INTF/encoder.. the easiest way to deal with this (ie. what
-        * we do now) is assume a fixed relationship between crtc's and
-        * encoders.  I'm not sure if there is ever a need to more freely
-        * assign crtcs to encoders, but if there is then we need to take
-        * care of error and vblank irq's that the crtc has registered,
-        * and also update user-requested vblank_mask.
-        */
-       encoder->possible_crtcs = BIT(0);
-       mdp5_crtc_set_intf(priv->crtcs[0], 3, INTF_HDMI);
-
+       encoder->possible_crtcs = (1 << priv->num_crtcs) - 1;;
        priv->encoders[priv->num_encoders++] = encoder;
 
        /* Construct bridge/connector for HDMI: */
index 03455b64a2458e28fdcdb724c42865f6280001de..2a731722d8407de40be9d2bbd82d6cabb8f8c737 100644 (file)
@@ -42,7 +42,10 @@ static void update_irq(struct mdp_kms *mdp_kms)
        mdp_kms->funcs->set_irqmask(mdp_kms, irqmask);
 }
 
-static void update_irq_unlocked(struct mdp_kms *mdp_kms)
+/* if an mdp_irq's irqmask has changed, such as when mdp5 crtc<->encoder
+ * link changes, this must be called to figure out the new global irqmask
+ */
+void mdp_irq_update(struct mdp_kms *mdp_kms)
 {
        unsigned long flags;
        spin_lock_irqsave(&list_lock, flags);
@@ -122,7 +125,7 @@ void mdp_irq_register(struct mdp_kms *mdp_kms, struct mdp_irq *irq)
        spin_unlock_irqrestore(&list_lock, flags);
 
        if (needs_update)
-               update_irq_unlocked(mdp_kms);
+               mdp_irq_update(mdp_kms);
 }
 
 void mdp_irq_unregister(struct mdp_kms *mdp_kms, struct mdp_irq *irq)
@@ -141,5 +144,5 @@ void mdp_irq_unregister(struct mdp_kms *mdp_kms, struct mdp_irq *irq)
        spin_unlock_irqrestore(&list_lock, flags);
 
        if (needs_update)
-               update_irq_unlocked(mdp_kms);
+               mdp_irq_update(mdp_kms);
 }
index 99557b5ad4fd35bedc3fd70b20571322571e9d76..b268ce95d3946fdf2f348250ce5cafeb15635b68 100644 (file)
@@ -75,7 +75,7 @@ void mdp_update_vblank_mask(struct mdp_kms *mdp_kms, uint32_t mask, bool enable)
 void mdp_irq_wait(struct mdp_kms *mdp_kms, uint32_t irqmask);
 void mdp_irq_register(struct mdp_kms *mdp_kms, struct mdp_irq *irq);
 void mdp_irq_unregister(struct mdp_kms *mdp_kms, struct mdp_irq *irq);
-
+void mdp_irq_update(struct mdp_kms *mdp_kms);
 
 /*
  * pixel format helpers:
index f0de412e13dc78bbc01e9b6dd7482c74358a14e9..191968256c5822ae0a7964db31377e5ba7b0e0ce 100644 (file)
@@ -23,10 +23,41 @@ struct msm_commit {
        struct drm_atomic_state *state;
        uint32_t fence;
        struct msm_fence_cb fence_cb;
+       uint32_t crtc_mask;
 };
 
 static void fence_cb(struct msm_fence_cb *cb);
 
+/* block until specified crtcs are no longer pending update, and
+ * atomically mark them as pending update
+ */
+static int start_atomic(struct msm_drm_private *priv, uint32_t crtc_mask)
+{
+       int ret;
+
+       spin_lock(&priv->pending_crtcs_event.lock);
+       ret = wait_event_interruptible_locked(priv->pending_crtcs_event,
+                       !(priv->pending_crtcs & crtc_mask));
+       if (ret == 0) {
+               DBG("start: %08x", crtc_mask);
+               priv->pending_crtcs |= crtc_mask;
+       }
+       spin_unlock(&priv->pending_crtcs_event.lock);
+
+       return ret;
+}
+
+/* clear specified crtcs (no longer pending update)
+ */
+static void end_atomic(struct msm_drm_private *priv, uint32_t crtc_mask)
+{
+       spin_lock(&priv->pending_crtcs_event.lock);
+       DBG("end: %08x", crtc_mask);
+       priv->pending_crtcs &= ~crtc_mask;
+       wake_up_all_locked(&priv->pending_crtcs_event);
+       spin_unlock(&priv->pending_crtcs_event.lock);
+}
+
 static struct msm_commit *new_commit(struct drm_atomic_state *state)
 {
        struct msm_commit *c = kzalloc(sizeof(*c), GFP_KERNEL);
@@ -58,12 +89,27 @@ static void complete_commit(struct msm_commit *c)
 
        drm_atomic_helper_commit_post_planes(dev, state);
 
+       /* NOTE: _wait_for_vblanks() only waits for vblank on
+        * enabled CRTCs.  So we end up faulting when disabling
+        * due to (potentially) unref'ing the outgoing fb's
+        * before the vblank when the disable has latched.
+        *
+        * But if it did wait on disabled (or newly disabled)
+        * CRTCs, that would be racy (ie. we could have missed
+        * the irq.  We need some way to poll for pipe shut
+        * down.  Or just live with occasionally hitting the
+        * timeout in the CRTC disable path (which really should
+        * not be critical path)
+        */
+
        drm_atomic_helper_wait_for_vblanks(dev, state);
 
        drm_atomic_helper_cleanup_planes(dev, state);
 
        drm_atomic_state_free(state);
 
+       end_atomic(dev->dev_private, c->crtc_mask);
+
        kfree(c);
 }
 
@@ -97,8 +143,9 @@ static void add_fb(struct msm_commit *c, struct drm_framebuffer *fb)
 int msm_atomic_commit(struct drm_device *dev,
                struct drm_atomic_state *state, bool async)
 {
-       struct msm_commit *c;
        int nplanes = dev->mode_config.num_total_plane;
+       int ncrtcs = dev->mode_config.num_crtc;
+       struct msm_commit *c;
        int i, ret;
 
        ret = drm_atomic_helper_prepare_planes(dev, state);
@@ -106,6 +153,18 @@ int msm_atomic_commit(struct drm_device *dev,
                return ret;
 
        c = new_commit(state);
+       if (!c)
+               return -ENOMEM;
+
+       /*
+        * Figure out what crtcs we have:
+        */
+       for (i = 0; i < ncrtcs; i++) {
+               struct drm_crtc *crtc = state->crtcs[i];
+               if (!crtc)
+                       continue;
+               c->crtc_mask |= (1 << drm_crtc_index(crtc));
+       }
 
        /*
         * Figure out what fence to wait for:
@@ -121,6 +180,14 @@ int msm_atomic_commit(struct drm_device *dev,
                        add_fb(c, new_state->fb);
        }
 
+       /*
+        * Wait for pending updates on any of the same crtc's and then
+        * mark our set of crtc's as busy:
+        */
+       ret = start_atomic(dev->dev_private, c->crtc_mask);
+       if (ret)
+               return ret;
+
        /*
         * This is the point of no return - everything below never fails except
         * when the hw goes bonghits. Which means we can commit the new state on
index c795217e1bfcc6051b72afd05cb09cfbbff34c2c..9a61546a0b05276cd313b0877306b02930fa2fa5 100644 (file)
@@ -193,6 +193,7 @@ static int msm_load(struct drm_device *dev, unsigned long flags)
 
        priv->wq = alloc_ordered_workqueue("msm", 0);
        init_waitqueue_head(&priv->fence_event);
+       init_waitqueue_head(&priv->pending_crtcs_event);
 
        INIT_LIST_HEAD(&priv->inactive_list);
        INIT_LIST_HEAD(&priv->fence_cbs);
index 136303818436726004b2f294c6c90d69ccdd2f05..b69ef2d5a26c0a0afa9896ed02a88a087f9cebfe 100644 (file)
@@ -96,6 +96,10 @@ struct msm_drm_private {
        /* callbacks deferred until bo is inactive: */
        struct list_head fence_cbs;
 
+       /* crtcs pending async atomic updates: */
+       uint32_t pending_crtcs;
+       wait_queue_head_t pending_crtcs_event;
+
        /* registered MMUs: */
        unsigned int num_mmus;
        struct msm_mmu *mmus[NUM_DOMAINS];
index 94d55e526b4e0732cba7fcf45a2ce725c2433637..1f3af13ccede96b0aa9ad17a49aca3dbaa358872 100644 (file)
@@ -190,8 +190,7 @@ fail_unlock:
 fail:
 
        if (ret) {
-               if (fbi)
-                       framebuffer_release(fbi);
+               framebuffer_release(fbi);
                if (fb) {
                        drm_framebuffer_unregister_private(fb);
                        drm_framebuffer_remove(fb);
index 4a6f0e49d5b5f0709d586e3dcf4e271a0c99c0f5..49dea4fb55ac5fc0c6aa4efa082326a8c892e08b 100644 (file)
@@ -535,8 +535,7 @@ void msm_gem_free_object(struct drm_gem_object *obj)
                        drm_free_large(msm_obj->pages);
 
        } else {
-               if (msm_obj->vaddr)
-                       vunmap(msm_obj->vaddr);
+               vunmap(msm_obj->vaddr);
                put_pages(obj);
        }
 
index 753a6def61e7ce474d73b21b9affe84ae8b1a861..3d1cfcb96b6bfd9e7dfa50e282d6e3761009f7e1 100644 (file)
@@ -28,6 +28,7 @@
 #include "nouveau_ttm.h"
 #include "nouveau_gem.h"
 
+#include "drm_legacy.h"
 static int
 nouveau_vram_manager_init(struct ttm_mem_type_manager *man, unsigned long psize)
 {
@@ -281,7 +282,7 @@ nouveau_ttm_mmap(struct file *filp, struct vm_area_struct *vma)
        struct nouveau_drm *drm = nouveau_drm(file_priv->minor->dev);
 
        if (unlikely(vma->vm_pgoff < DRM_FILE_PAGE_OFFSET))
-               return -EINVAL;
+               return drm_legacy_mmap(filp, vma);
 
        return ttm_bo_mmap(filp, vma, &drm->ttm.bdev);
 }
index 3367960286a6f162455e0363a54dace2c6882883..978993fa3a360ef426b6dc48a3c287c3eda0cf48 100644 (file)
@@ -168,7 +168,7 @@ static int tegra_dc_setup_window(struct tegra_dc *dc, unsigned int index,
                                 const struct tegra_dc_window *window)
 {
        unsigned h_offset, v_offset, h_size, v_size, h_dda, v_dda, bpp;
-       unsigned long value;
+       unsigned long value, flags;
        bool yuv, planar;
 
        /*
@@ -181,6 +181,8 @@ static int tegra_dc_setup_window(struct tegra_dc *dc, unsigned int index,
        else
                bpp = planar ? 1 : 2;
 
+       spin_lock_irqsave(&dc->lock, flags);
+
        value = WINDOW_A_SELECT << index;
        tegra_dc_writel(dc, value, DC_CMD_DISPLAY_WINDOW_HEADER);
 
@@ -273,6 +275,7 @@ static int tegra_dc_setup_window(struct tegra_dc *dc, unsigned int index,
 
                case TEGRA_BO_TILING_MODE_BLOCK:
                        DRM_ERROR("hardware doesn't support block linear mode\n");
+                       spin_unlock_irqrestore(&dc->lock, flags);
                        return -EINVAL;
                }
 
@@ -331,6 +334,8 @@ static int tegra_dc_setup_window(struct tegra_dc *dc, unsigned int index,
 
        tegra_dc_window_commit(dc, index);
 
+       spin_unlock_irqrestore(&dc->lock, flags);
+
        return 0;
 }
 
@@ -338,11 +343,14 @@ static int tegra_window_plane_disable(struct drm_plane *plane)
 {
        struct tegra_dc *dc = to_tegra_dc(plane->crtc);
        struct tegra_plane *p = to_tegra_plane(plane);
+       unsigned long flags;
        u32 value;
 
        if (!plane->crtc)
                return 0;
 
+       spin_lock_irqsave(&dc->lock, flags);
+
        value = WINDOW_A_SELECT << p->index;
        tegra_dc_writel(dc, value, DC_CMD_DISPLAY_WINDOW_HEADER);
 
@@ -352,6 +360,8 @@ static int tegra_window_plane_disable(struct drm_plane *plane)
 
        tegra_dc_window_commit(dc, p->index);
 
+       spin_unlock_irqrestore(&dc->lock, flags);
+
        return 0;
 }
 
@@ -699,14 +709,16 @@ static int tegra_dc_set_base(struct tegra_dc *dc, int x, int y,
        struct tegra_bo *bo = tegra_fb_get_plane(fb, 0);
        unsigned int h_offset = 0, v_offset = 0;
        struct tegra_bo_tiling tiling;
+       unsigned long value, flags;
        unsigned int format, swap;
-       unsigned long value;
        int err;
 
        err = tegra_fb_get_tiling(fb, &tiling);
        if (err < 0)
                return err;
 
+       spin_lock_irqsave(&dc->lock, flags);
+
        tegra_dc_writel(dc, WINDOW_A_SELECT, DC_CMD_DISPLAY_WINDOW_HEADER);
 
        value = fb->offsets[0] + y * fb->pitches[0] +
@@ -752,6 +764,7 @@ static int tegra_dc_set_base(struct tegra_dc *dc, int x, int y,
 
                case TEGRA_BO_TILING_MODE_BLOCK:
                        DRM_ERROR("hardware doesn't support block linear mode\n");
+                       spin_unlock_irqrestore(&dc->lock, flags);
                        return -EINVAL;
                }
 
@@ -778,6 +791,8 @@ static int tegra_dc_set_base(struct tegra_dc *dc, int x, int y,
        tegra_dc_writel(dc, value << 8, DC_CMD_STATE_CONTROL);
        tegra_dc_writel(dc, value, DC_CMD_STATE_CONTROL);
 
+       spin_unlock_irqrestore(&dc->lock, flags);
+
        return 0;
 }
 
@@ -814,23 +829,32 @@ static void tegra_dc_finish_page_flip(struct tegra_dc *dc)
        unsigned long flags, base;
        struct tegra_bo *bo;
 
-       if (!dc->event)
+       spin_lock_irqsave(&drm->event_lock, flags);
+
+       if (!dc->event) {
+               spin_unlock_irqrestore(&drm->event_lock, flags);
                return;
+       }
 
        bo = tegra_fb_get_plane(crtc->primary->fb, 0);
 
+       spin_lock_irqsave(&dc->lock, flags);
+
        /* check if new start address has been latched */
+       tegra_dc_writel(dc, WINDOW_A_SELECT, DC_CMD_DISPLAY_WINDOW_HEADER);
        tegra_dc_writel(dc, READ_MUX, DC_CMD_STATE_ACCESS);
        base = tegra_dc_readl(dc, DC_WINBUF_START_ADDR);
        tegra_dc_writel(dc, 0, DC_CMD_STATE_ACCESS);
 
+       spin_unlock_irqrestore(&dc->lock, flags);
+
        if (base == bo->paddr + crtc->primary->fb->offsets[0]) {
-               spin_lock_irqsave(&drm->event_lock, flags);
-               drm_send_vblank_event(drm, dc->pipe, dc->event);
-               drm_vblank_put(drm, dc->pipe);
+               drm_crtc_send_vblank_event(crtc, dc->event);
+               drm_crtc_vblank_put(crtc);
                dc->event = NULL;
-               spin_unlock_irqrestore(&drm->event_lock, flags);
        }
+
+       spin_unlock_irqrestore(&drm->event_lock, flags);
 }
 
 void tegra_dc_cancel_page_flip(struct drm_crtc *crtc, struct drm_file *file)
@@ -843,7 +867,7 @@ void tegra_dc_cancel_page_flip(struct drm_crtc *crtc, struct drm_file *file)
 
        if (dc->event && dc->event->base.file_priv == file) {
                dc->event->base.destroy(&dc->event->base);
-               drm_vblank_put(drm, dc->pipe);
+               drm_crtc_vblank_put(crtc);
                dc->event = NULL;
        }
 
@@ -853,16 +877,16 @@ void tegra_dc_cancel_page_flip(struct drm_crtc *crtc, struct drm_file *file)
 static int tegra_dc_page_flip(struct drm_crtc *crtc, struct drm_framebuffer *fb,
                              struct drm_pending_vblank_event *event, uint32_t page_flip_flags)
 {
+       unsigned int pipe = drm_crtc_index(crtc);
        struct tegra_dc *dc = to_tegra_dc(crtc);
-       struct drm_device *drm = crtc->dev;
 
        if (dc->event)
                return -EBUSY;
 
        if (event) {
-               event->pipe = dc->pipe;
+               event->pipe = pipe;
                dc->event = event;
-               drm_vblank_get(drm, dc->pipe);
+               drm_crtc_vblank_get(crtc);
        }
 
        tegra_dc_set_base(dc, 0, 0, fb);
@@ -1127,7 +1151,7 @@ static irqreturn_t tegra_dc_irq(int irq, void *data)
                /*
                dev_dbg(dc->dev, "%s(): vertical blank\n", __func__);
                */
-               drm_handle_vblank(dc->base.dev, dc->pipe);
+               drm_crtc_handle_vblank(&dc->base);
                tegra_dc_finish_page_flip(dc);
        }
 
index e549afeece1ff12c899afc9f21dd52ff5e3e64ff..d4f827593dfa2041a386dba733f9436cbed1d111 100644 (file)
@@ -694,24 +694,28 @@ static const struct file_operations tegra_drm_fops = {
        .llseek = noop_llseek,
 };
 
-static struct drm_crtc *tegra_crtc_from_pipe(struct drm_device *drm, int pipe)
+static struct drm_crtc *tegra_crtc_from_pipe(struct drm_device *drm,
+                                            unsigned int pipe)
 {
        struct drm_crtc *crtc;
 
        list_for_each_entry(crtc, &drm->mode_config.crtc_list, head) {
-               struct tegra_dc *dc = to_tegra_dc(crtc);
-
-               if (dc->pipe == pipe)
+               if (pipe == drm_crtc_index(crtc))
                        return crtc;
        }
 
        return NULL;
 }
 
-static u32 tegra_drm_get_vblank_counter(struct drm_device *dev, int crtc)
+static u32 tegra_drm_get_vblank_counter(struct drm_device *drm, int pipe)
 {
+       struct drm_crtc *crtc = tegra_crtc_from_pipe(drm, pipe);
+
+       if (!crtc)
+               return 0;
+
        /* TODO: implement real hardware counter using syncpoints */
-       return drm_vblank_count(dev, crtc);
+       return drm_crtc_vblank_count(crtc);
 }
 
 static int tegra_drm_enable_vblank(struct drm_device *drm, int pipe)
index da32086cbeaf28bbe0c0528eeeac4c0bb9fcb326..8777b7f757916a704ceaec670c44d34a0aee813d 100644 (file)
@@ -216,32 +216,58 @@ static void tegra_bo_free(struct drm_device *drm, struct tegra_bo *bo)
        }
 }
 
-static int tegra_bo_get_pages(struct drm_device *drm, struct tegra_bo *bo,
-                             size_t size)
+static int tegra_bo_get_pages(struct drm_device *drm, struct tegra_bo *bo)
 {
+       struct scatterlist *s;
+       struct sg_table *sgt;
+       unsigned int i;
+
        bo->pages = drm_gem_get_pages(&bo->gem);
        if (IS_ERR(bo->pages))
                return PTR_ERR(bo->pages);
 
-       bo->num_pages = size >> PAGE_SHIFT;
-
-       bo->sgt = drm_prime_pages_to_sg(bo->pages, bo->num_pages);
-       if (IS_ERR(bo->sgt)) {
-               drm_gem_put_pages(&bo->gem, bo->pages, false, false);
-               return PTR_ERR(bo->sgt);
+       bo->num_pages = bo->gem.size >> PAGE_SHIFT;
+
+       sgt = drm_prime_pages_to_sg(bo->pages, bo->num_pages);
+       if (IS_ERR(sgt))
+               goto put_pages;
+
+       /*
+        * Fake up the SG table so that dma_map_sg() can be used to flush the
+        * pages associated with it. Note that this relies on the fact that
+        * the DMA API doesn't hook into IOMMU on Tegra, therefore mapping is
+        * only cache maintenance.
+        *
+        * TODO: Replace this by drm_clflash_sg() once it can be implemented
+        * without relying on symbols that are not exported.
+        */
+       for_each_sg(sgt->sgl, s, sgt->nents, i)
+               sg_dma_address(s) = sg_phys(s);
+
+       if (dma_map_sg(drm->dev, sgt->sgl, sgt->nents, DMA_TO_DEVICE) == 0) {
+               sgt = ERR_PTR(-ENOMEM);
+               goto release_sgt;
        }
 
+       bo->sgt = sgt;
+
        return 0;
+
+release_sgt:
+       sg_free_table(sgt);
+       kfree(sgt);
+put_pages:
+       drm_gem_put_pages(&bo->gem, bo->pages, false, false);
+       return PTR_ERR(sgt);
 }
 
-static int tegra_bo_alloc(struct drm_device *drm, struct tegra_bo *bo,
-                         size_t size)
+static int tegra_bo_alloc(struct drm_device *drm, struct tegra_bo *bo)
 {
        struct tegra_drm *tegra = drm->dev_private;
        int err;
 
        if (tegra->domain) {
-               err = tegra_bo_get_pages(drm, bo, size);
+               err = tegra_bo_get_pages(drm, bo);
                if (err < 0)
                        return err;
 
@@ -251,6 +277,8 @@ static int tegra_bo_alloc(struct drm_device *drm, struct tegra_bo *bo,
                        return err;
                }
        } else {
+               size_t size = bo->gem.size;
+
                bo->vaddr = dma_alloc_writecombine(drm->dev, size, &bo->paddr,
                                                   GFP_KERNEL | __GFP_NOWARN);
                if (!bo->vaddr) {
@@ -274,7 +302,7 @@ struct tegra_bo *tegra_bo_create(struct drm_device *drm, size_t size,
        if (IS_ERR(bo))
                return bo;
 
-       err = tegra_bo_alloc(drm, bo, size);
+       err = tegra_bo_alloc(drm, bo);
        if (err < 0)
                goto release;
 
index 8ba35c622e2202a889a3a06706bdc93e035fb841..e1b2e8b98af7cde2c7276e915cd90ea4794b317e 100644 (file)
@@ -901,11 +901,15 @@ extern int drm_vblank_init(struct drm_device *dev, int num_crtcs);
 extern int drm_wait_vblank(struct drm_device *dev, void *data,
                           struct drm_file *filp);
 extern u32 drm_vblank_count(struct drm_device *dev, int crtc);
+extern u32 drm_crtc_vblank_count(struct drm_crtc *crtc);
 extern u32 drm_vblank_count_and_time(struct drm_device *dev, int crtc,
                                     struct timeval *vblanktime);
 extern void drm_send_vblank_event(struct drm_device *dev, int crtc,
                                     struct drm_pending_vblank_event *e);
+extern void drm_crtc_send_vblank_event(struct drm_crtc *crtc,
+                                      struct drm_pending_vblank_event *e);
 extern bool drm_handle_vblank(struct drm_device *dev, int crtc);
+extern bool drm_crtc_handle_vblank(struct drm_crtc *crtc);
 extern int drm_vblank_get(struct drm_device *dev, int crtc);
 extern void drm_vblank_put(struct drm_device *dev, int crtc);
 extern int drm_crtc_vblank_get(struct drm_crtc *crtc);