Merge branch 'drm-fixes' of git://people.freedesktop.org/~airlied/linux
authorLinus Torvalds <torvalds@linux-foundation.org>
Mon, 23 Sep 2013 02:51:49 +0000 (19:51 -0700)
committerLinus Torvalds <torvalds@linux-foundation.org>
Mon, 23 Sep 2013 02:51:49 +0000 (19:51 -0700)
Pull drm fixes from Dave Airlie:
 - some small fixes for msm and exynos
 - a regression revert affecting nouveau users with old userspace
 - intel pageflip deadlock and gpu hang fixes, hsw modesetting hangs

* 'drm-fixes' of git://people.freedesktop.org/~airlied/linux: (22 commits)
  Revert "drm: mark context support as a legacy subsystem"
  drm/i915: Don't enable the cursor on a disable pipe
  drm/i915: do not update cursor in crtc mode set
  drm/exynos: fix return value check in lowlevel_buffer_allocate()
  drm/exynos: Fix address space warnings in exynos_drm_fbdev.c
  drm/exynos: Fix address space warning in exynos_drm_buf.c
  drm/exynos: Remove redundant OF dependency
  drm/msm: drop unnecessary set_need_resched()
  drm/i915: kill set_need_resched
  drm/msm: fix potential NULL pointer dereference
  drm/i915/dvo: set crtc timings again for panel fixed modes
  drm/i915/sdvo: Robustify the dtd<->drm_mode conversions
  drm/msm: workaround for missing irq
  drm/msm: return -EBUSY if bo still active
  drm/msm: fix return value check in ERR_PTR()
  drm/msm: fix cmdstream size check
  drm/msm: hangcheck harder
  drm/msm: handle read vs write fences
  drm/i915/sdvo: Fully translate sync flags in the dtd->mode conversion
  drm/i915: Use proper print format for debug prints
  ...

23 files changed:
drivers/gpu/drm/drm_context.c
drivers/gpu/drm/drm_fops.c
drivers/gpu/drm/drm_stub.c
drivers/gpu/drm/exynos/Kconfig
drivers/gpu/drm/exynos/exynos_drm_buf.c
drivers/gpu/drm/exynos/exynos_drm_fbdev.c
drivers/gpu/drm/i915/i915_gem.c
drivers/gpu/drm/i915/i915_irq.c
drivers/gpu/drm/i915/intel_ddi.c
drivers/gpu/drm/i915/intel_display.c
drivers/gpu/drm/i915/intel_drv.h
drivers/gpu/drm/i915/intel_dvo.c
drivers/gpu/drm/i915/intel_panel.c
drivers/gpu/drm/i915/intel_pm.c
drivers/gpu/drm/i915/intel_sdvo.c
drivers/gpu/drm/msm/adreno/adreno_gpu.c
drivers/gpu/drm/msm/msm_drv.c
drivers/gpu/drm/msm/msm_drv.h
drivers/gpu/drm/msm/msm_gem.c
drivers/gpu/drm/msm/msm_gem.h
drivers/gpu/drm/msm/msm_gem_submit.c
drivers/gpu/drm/msm/msm_gpu.c
include/drm/drmP.h

index b4fb86d89850a31c3cc9424f4b4148831c59922f..224ff965bcf7de624c3b62b6db153bda090ea4a9 100644 (file)
 
 #include <drm/drmP.h>
 
+/******************************************************************/
+/** \name Context bitmap support */
+/*@{*/
+
 /**
  * Free a handle from the context bitmap.
  *
  * in drm_device::ctx_idr, while holding the drm_device::struct_mutex
  * lock.
  */
-static void drm_ctxbitmap_free(struct drm_device * dev, int ctx_handle)
+void drm_ctxbitmap_free(struct drm_device * dev, int ctx_handle)
 {
-       if (drm_core_check_feature(dev, DRIVER_MODESET))
-               return;
-
        mutex_lock(&dev->struct_mutex);
        idr_remove(&dev->ctx_idr, ctx_handle);
        mutex_unlock(&dev->struct_mutex);
 }
 
-/******************************************************************/
-/** \name Context bitmap support */
-/*@{*/
-
-void drm_legacy_ctxbitmap_release(struct drm_device *dev,
-                                 struct drm_file *file_priv)
-{
-       if (drm_core_check_feature(dev, DRIVER_MODESET))
-               return;
-
-       mutex_lock(&dev->ctxlist_mutex);
-       if (!list_empty(&dev->ctxlist)) {
-               struct drm_ctx_list *pos, *n;
-
-               list_for_each_entry_safe(pos, n, &dev->ctxlist, head) {
-                       if (pos->tag == file_priv &&
-                           pos->handle != DRM_KERNEL_CONTEXT) {
-                               if (dev->driver->context_dtor)
-                                       dev->driver->context_dtor(dev,
-                                                                 pos->handle);
-
-                               drm_ctxbitmap_free(dev, pos->handle);
-
-                               list_del(&pos->head);
-                               kfree(pos);
-                               --dev->ctx_count;
-                       }
-               }
-       }
-       mutex_unlock(&dev->ctxlist_mutex);
-}
-
 /**
  * Context bitmap allocation.
  *
@@ -121,12 +90,10 @@ static int drm_ctxbitmap_next(struct drm_device * dev)
  *
  * Initialise the drm_device::ctx_idr
  */
-void drm_legacy_ctxbitmap_init(struct drm_device * dev)
+int drm_ctxbitmap_init(struct drm_device * dev)
 {
-       if (drm_core_check_feature(dev, DRIVER_MODESET))
-               return;
-
        idr_init(&dev->ctx_idr);
+       return 0;
 }
 
 /**
@@ -137,7 +104,7 @@ void drm_legacy_ctxbitmap_init(struct drm_device * dev)
  * Free all idr members using drm_ctx_sarea_free helper function
  * while holding the drm_device::struct_mutex lock.
  */
-void drm_legacy_ctxbitmap_cleanup(struct drm_device * dev)
+void drm_ctxbitmap_cleanup(struct drm_device * dev)
 {
        mutex_lock(&dev->struct_mutex);
        idr_destroy(&dev->ctx_idr);
@@ -169,9 +136,6 @@ int drm_getsareactx(struct drm_device *dev, void *data,
        struct drm_local_map *map;
        struct drm_map_list *_entry;
 
-       if (drm_core_check_feature(dev, DRIVER_MODESET))
-               return -EINVAL;
-
        mutex_lock(&dev->struct_mutex);
 
        map = idr_find(&dev->ctx_idr, request->ctx_id);
@@ -216,9 +180,6 @@ int drm_setsareactx(struct drm_device *dev, void *data,
        struct drm_local_map *map = NULL;
        struct drm_map_list *r_list = NULL;
 
-       if (drm_core_check_feature(dev, DRIVER_MODESET))
-               return -EINVAL;
-
        mutex_lock(&dev->struct_mutex);
        list_for_each_entry(r_list, &dev->maplist, head) {
                if (r_list->map
@@ -319,9 +280,6 @@ int drm_resctx(struct drm_device *dev, void *data,
        struct drm_ctx ctx;
        int i;
 
-       if (drm_core_check_feature(dev, DRIVER_MODESET))
-               return -EINVAL;
-
        if (res->count >= DRM_RESERVED_CONTEXTS) {
                memset(&ctx, 0, sizeof(ctx));
                for (i = 0; i < DRM_RESERVED_CONTEXTS; i++) {
@@ -352,9 +310,6 @@ int drm_addctx(struct drm_device *dev, void *data,
        struct drm_ctx_list *ctx_entry;
        struct drm_ctx *ctx = data;
 
-       if (drm_core_check_feature(dev, DRIVER_MODESET))
-               return -EINVAL;
-
        ctx->handle = drm_ctxbitmap_next(dev);
        if (ctx->handle == DRM_KERNEL_CONTEXT) {
                /* Skip kernel's context and get a new one. */
@@ -398,9 +353,6 @@ int drm_getctx(struct drm_device *dev, void *data, struct drm_file *file_priv)
 {
        struct drm_ctx *ctx = data;
 
-       if (drm_core_check_feature(dev, DRIVER_MODESET))
-               return -EINVAL;
-
        /* This is 0, because we don't handle any context flags */
        ctx->flags = 0;
 
@@ -423,9 +375,6 @@ int drm_switchctx(struct drm_device *dev, void *data,
 {
        struct drm_ctx *ctx = data;
 
-       if (drm_core_check_feature(dev, DRIVER_MODESET))
-               return -EINVAL;
-
        DRM_DEBUG("%d\n", ctx->handle);
        return drm_context_switch(dev, dev->last_context, ctx->handle);
 }
@@ -446,9 +395,6 @@ int drm_newctx(struct drm_device *dev, void *data,
 {
        struct drm_ctx *ctx = data;
 
-       if (drm_core_check_feature(dev, DRIVER_MODESET))
-               return -EINVAL;
-
        DRM_DEBUG("%d\n", ctx->handle);
        drm_context_switch_complete(dev, file_priv, ctx->handle);
 
@@ -471,9 +417,6 @@ int drm_rmctx(struct drm_device *dev, void *data,
 {
        struct drm_ctx *ctx = data;
 
-       if (drm_core_check_feature(dev, DRIVER_MODESET))
-               return -EINVAL;
-
        DRM_DEBUG("%d\n", ctx->handle);
        if (ctx->handle != DRM_KERNEL_CONTEXT) {
                if (dev->driver->context_dtor)
index 4be8e09a32ef730db4740f6f69e52f91ca829112..3f84277d7036b3f843120fb4145dc081010d3d0d 100644 (file)
@@ -439,7 +439,26 @@ int drm_release(struct inode *inode, struct file *filp)
        if (dev->driver->driver_features & DRIVER_GEM)
                drm_gem_release(dev, file_priv);
 
-       drm_legacy_ctxbitmap_release(dev, file_priv);
+       mutex_lock(&dev->ctxlist_mutex);
+       if (!list_empty(&dev->ctxlist)) {
+               struct drm_ctx_list *pos, *n;
+
+               list_for_each_entry_safe(pos, n, &dev->ctxlist, head) {
+                       if (pos->tag == file_priv &&
+                           pos->handle != DRM_KERNEL_CONTEXT) {
+                               if (dev->driver->context_dtor)
+                                       dev->driver->context_dtor(dev,
+                                                                 pos->handle);
+
+                               drm_ctxbitmap_free(dev, pos->handle);
+
+                               list_del(&pos->head);
+                               kfree(pos);
+                               --dev->ctx_count;
+                       }
+               }
+       }
+       mutex_unlock(&dev->ctxlist_mutex);
 
        mutex_lock(&dev->struct_mutex);
 
index e7eb0276f7f1968e6c71997eab517fd3a6746fac..39d864576be4a4d5f5957cdbf1e3112b1322a018 100644 (file)
@@ -292,7 +292,13 @@ int drm_fill_in_dev(struct drm_device *dev,
                        goto error_out_unreg;
        }
 
-       drm_legacy_ctxbitmap_init(dev);
+
+
+       retcode = drm_ctxbitmap_init(dev);
+       if (retcode) {
+               DRM_ERROR("Cannot allocate memory for context bitmap.\n");
+               goto error_out_unreg;
+       }
 
        if (driver->driver_features & DRIVER_GEM) {
                retcode = drm_gem_init(dev);
@@ -446,7 +452,7 @@ void drm_put_dev(struct drm_device *dev)
                drm_rmmap(dev, r_list->map);
        drm_ht_remove(&dev->map_hash);
 
-       drm_legacy_ctxbitmap_cleanup(dev);
+       drm_ctxbitmap_cleanup(dev);
 
        if (drm_core_check_feature(dev, DRIVER_MODESET))
                drm_put_minor(&dev->control);
index 4752f223e5b28a2fb793eb5b83be0fefb89a7ac2..45b6ef595965b7cb7391125d8b3a4caf2703b2b5 100644 (file)
@@ -56,7 +56,7 @@ config DRM_EXYNOS_IPP
 
 config DRM_EXYNOS_FIMC
        bool "Exynos DRM FIMC"
-       depends on DRM_EXYNOS_IPP && MFD_SYSCON && OF
+       depends on DRM_EXYNOS_IPP && MFD_SYSCON
        help
          Choose this option if you want to use Exynos FIMC for DRM.
 
index 3445a0f3a6b29dc6110d0e3a950a23de92a4098c..9c8088462c26f970d42b2fb40dae86490e51d3f6 100644 (file)
@@ -63,7 +63,8 @@ static int lowlevel_buffer_allocate(struct drm_device *dev,
                        return -ENOMEM;
                }
 
-               buf->kvaddr = dma_alloc_attrs(dev->dev, buf->size,
+               buf->kvaddr = (void __iomem *)dma_alloc_attrs(dev->dev,
+                                       buf->size,
                                        &buf->dma_addr, GFP_KERNEL,
                                        &buf->dma_attrs);
                if (!buf->kvaddr) {
@@ -90,9 +91,9 @@ static int lowlevel_buffer_allocate(struct drm_device *dev,
        }
 
        buf->sgt = drm_prime_pages_to_sg(buf->pages, nr_pages);
-       if (!buf->sgt) {
+       if (IS_ERR(buf->sgt)) {
                DRM_ERROR("failed to get sg table.\n");
-               ret = -ENOMEM;
+               ret = PTR_ERR(buf->sgt);
                goto err_free_attrs;
        }
 
index 78e868bcf1ecc364638e4ce3343cc66f260599f0..e7c2f2d07f193b0393052be2e1bf32921b804da9 100644 (file)
@@ -99,12 +99,13 @@ static int exynos_drm_fbdev_update(struct drm_fb_helper *helper,
                if (is_drm_iommu_supported(dev)) {
                        unsigned int nr_pages = buffer->size >> PAGE_SHIFT;
 
-                       buffer->kvaddr = vmap(buffer->pages, nr_pages, VM_MAP,
+                       buffer->kvaddr = (void __iomem *) vmap(buffer->pages,
+                                       nr_pages, VM_MAP,
                                        pgprot_writecombine(PAGE_KERNEL));
                } else {
                        phys_addr_t dma_addr = buffer->dma_addr;
                        if (dma_addr)
-                               buffer->kvaddr = phys_to_virt(dma_addr);
+                               buffer->kvaddr = (void __iomem *)phys_to_virt(dma_addr);
                        else
                                buffer->kvaddr = (void __iomem *)NULL;
                }
index 8507c6d1e642d872c48f41834a5dbeca53d99c6b..df9253d890ee1fbb60482066312a46e7701bf2d4 100644 (file)
@@ -1392,14 +1392,11 @@ out:
                if (i915_terminally_wedged(&dev_priv->gpu_error))
                        return VM_FAULT_SIGBUS;
        case -EAGAIN:
-               /* Give the error handler a chance to run and move the
-                * objects off the GPU active list. Next time we service the
-                * fault, we should be able to transition the page into the
-                * GTT without touching the GPU (and so avoid further
-                * EIO/EGAIN). If the GPU is wedged, then there is no issue
-                * with coherency, just lost writes.
+               /*
+                * EAGAIN means the gpu is hung and we'll wait for the error
+                * handler to reset everything when re-faulting in
+                * i915_mutex_lock_interruptible.
                 */
-               set_need_resched();
        case 0:
        case -ERESTARTSYS:
        case -EINTR:
index 83cce0cdb7691a9aa6024defc01c869a57b4a90a..4b91228fd9bd8e50e1319816a9fe53b6f166ec68 100644 (file)
@@ -1469,6 +1469,34 @@ static irqreturn_t ironlake_irq_handler(int irq, void *arg)
        return ret;
 }
 
+static void i915_error_wake_up(struct drm_i915_private *dev_priv,
+                              bool reset_completed)
+{
+       struct intel_ring_buffer *ring;
+       int i;
+
+       /*
+        * Notify all waiters for GPU completion events that reset state has
+        * been changed, and that they need to restart their wait after
+        * checking for potential errors (and bail out to drop locks if there is
+        * a gpu reset pending so that i915_error_work_func can acquire them).
+        */
+
+       /* Wake up __wait_seqno, potentially holding dev->struct_mutex. */
+       for_each_ring(ring, dev_priv, i)
+               wake_up_all(&ring->irq_queue);
+
+       /* Wake up intel_crtc_wait_for_pending_flips, holding crtc->mutex. */
+       wake_up_all(&dev_priv->pending_flip_queue);
+
+       /*
+        * Signal tasks blocked in i915_gem_wait_for_error that the pending
+        * reset state is cleared.
+        */
+       if (reset_completed)
+               wake_up_all(&dev_priv->gpu_error.reset_queue);
+}
+
 /**
  * i915_error_work_func - do process context error handling work
  * @work: work struct
@@ -1483,11 +1511,10 @@ static void i915_error_work_func(struct work_struct *work)
        drm_i915_private_t *dev_priv = container_of(error, drm_i915_private_t,
                                                    gpu_error);
        struct drm_device *dev = dev_priv->dev;
-       struct intel_ring_buffer *ring;
        char *error_event[] = { I915_ERROR_UEVENT "=1", NULL };
        char *reset_event[] = { I915_RESET_UEVENT "=1", NULL };
        char *reset_done_event[] = { I915_ERROR_UEVENT "=0", NULL };
-       int i, ret;
+       int ret;
 
        kobject_uevent_env(&dev->primary->kdev.kobj, KOBJ_CHANGE, error_event);
 
@@ -1506,8 +1533,16 @@ static void i915_error_work_func(struct work_struct *work)
                kobject_uevent_env(&dev->primary->kdev.kobj, KOBJ_CHANGE,
                                   reset_event);
 
+               /*
+                * All state reset _must_ be completed before we update the
+                * reset counter, for otherwise waiters might miss the reset
+                * pending state and not properly drop locks, resulting in
+                * deadlocks with the reset work.
+                */
                ret = i915_reset(dev);
 
+               intel_display_handle_reset(dev);
+
                if (ret == 0) {
                        /*
                         * After all the gem state is reset, increment the reset
@@ -1528,12 +1563,11 @@ static void i915_error_work_func(struct work_struct *work)
                        atomic_set(&error->reset_counter, I915_WEDGED);
                }
 
-               for_each_ring(ring, dev_priv, i)
-                       wake_up_all(&ring->irq_queue);
-
-               intel_display_handle_reset(dev);
-
-               wake_up_all(&dev_priv->gpu_error.reset_queue);
+               /*
+                * Note: The wake_up also serves as a memory barrier so that
+                * waiters see the update value of the reset counter atomic_t.
+                */
+               i915_error_wake_up(dev_priv, true);
        }
 }
 
@@ -1642,8 +1676,6 @@ static void i915_report_and_clear_eir(struct drm_device *dev)
 void i915_handle_error(struct drm_device *dev, bool wedged)
 {
        struct drm_i915_private *dev_priv = dev->dev_private;
-       struct intel_ring_buffer *ring;
-       int i;
 
        i915_capture_error_state(dev);
        i915_report_and_clear_eir(dev);
@@ -1653,11 +1685,19 @@ void i915_handle_error(struct drm_device *dev, bool wedged)
                                &dev_priv->gpu_error.reset_counter);
 
                /*
-                * Wakeup waiting processes so that the reset work item
-                * doesn't deadlock trying to grab various locks.
+                * Wakeup waiting processes so that the reset work function
+                * i915_error_work_func doesn't deadlock trying to grab various
+                * locks. By bumping the reset counter first, the woken
+                * processes will see a reset in progress and back off,
+                * releasing their locks and then wait for the reset completion.
+                * We must do this for _all_ gpu waiters that might hold locks
+                * that the reset work needs to acquire.
+                *
+                * Note: The wake_up serves as the required memory barrier to
+                * ensure that the waiters see the updated value of the reset
+                * counter atomic_t.
                 */
-               for_each_ring(ring, dev_priv, i)
-                       wake_up_all(&ring->irq_queue);
+               i915_error_wake_up(dev_priv, false);
        }
 
        /*
index 63aca49d11a843a6ad6ae1a62dc11d0b3bfd470c..63de2701b97403a82ffd221424d5b5b9acda5843 100644 (file)
@@ -778,7 +778,7 @@ void intel_ddi_enable_transcoder_func(struct drm_crtc *crtc)
                        /* Can only use the always-on power well for eDP when
                         * not using the panel fitter, and when not using motion
                          * blur mitigation (which we don't support). */
-                       if (intel_crtc->config.pch_pfit.size)
+                       if (intel_crtc->config.pch_pfit.enabled)
                                temp |= TRANS_DDI_EDP_INPUT_A_ONOFF;
                        else
                                temp |= TRANS_DDI_EDP_INPUT_A_ON;
index 2489d0b4c7d2db8a8b5d74c04107f1b405c8ad35..d8a1d98693e7004524aedfb1e3b91e88508d7c95 100644 (file)
@@ -2249,7 +2249,7 @@ intel_pipe_set_base(struct drm_crtc *crtc, int x, int y,
                I915_WRITE(PIPESRC(intel_crtc->pipe),
                           ((crtc->mode.hdisplay - 1) << 16) |
                           (crtc->mode.vdisplay - 1));
-               if (!intel_crtc->config.pch_pfit.size &&
+               if (!intel_crtc->config.pch_pfit.enabled &&
                    (intel_pipe_has_type(crtc, INTEL_OUTPUT_LVDS) ||
                     intel_pipe_has_type(crtc, INTEL_OUTPUT_EDP))) {
                        I915_WRITE(PF_CTL(intel_crtc->pipe), 0);
@@ -3203,7 +3203,7 @@ static void ironlake_pfit_enable(struct intel_crtc *crtc)
        struct drm_i915_private *dev_priv = dev->dev_private;
        int pipe = crtc->pipe;
 
-       if (crtc->config.pch_pfit.size) {
+       if (crtc->config.pch_pfit.enabled) {
                /* Force use of hard-coded filter coefficients
                 * as some pre-programmed values are broken,
                 * e.g. x201.
@@ -3428,7 +3428,7 @@ static void ironlake_pfit_disable(struct intel_crtc *crtc)
 
        /* To avoid upsetting the power well on haswell only disable the pfit if
         * it's in use. The hw state code will make sure we get this right. */
-       if (crtc->config.pch_pfit.size) {
+       if (crtc->config.pch_pfit.enabled) {
                I915_WRITE(PF_CTL(pipe), 0);
                I915_WRITE(PF_WIN_POS(pipe), 0);
                I915_WRITE(PF_WIN_SZ(pipe), 0);
@@ -4877,9 +4877,6 @@ static int i9xx_crtc_mode_set(struct drm_crtc *crtc,
                return -EINVAL;
        }
 
-       /* Ensure that the cursor is valid for the new mode before changing... */
-       intel_crtc_update_cursor(crtc, true);
-
        if (is_lvds && dev_priv->lvds_downclock_avail) {
                /*
                 * Ensure we match the reduced clock's P to the target clock.
@@ -5768,9 +5765,6 @@ static int ironlake_crtc_mode_set(struct drm_crtc *crtc,
                intel_crtc->config.dpll.p2 = clock.p2;
        }
 
-       /* Ensure that the cursor is valid for the new mode before changing... */
-       intel_crtc_update_cursor(crtc, true);
-
        /* CPU eDP is the only output that doesn't need a PCH PLL of its own. */
        if (intel_crtc->config.has_pch_encoder) {
                fp = i9xx_dpll_compute_fp(&intel_crtc->config.dpll);
@@ -5859,6 +5853,7 @@ static void ironlake_get_pfit_config(struct intel_crtc *crtc,
        tmp = I915_READ(PF_CTL(crtc->pipe));
 
        if (tmp & PF_ENABLE) {
+               pipe_config->pch_pfit.enabled = true;
                pipe_config->pch_pfit.pos = I915_READ(PF_WIN_POS(crtc->pipe));
                pipe_config->pch_pfit.size = I915_READ(PF_WIN_SZ(crtc->pipe));
 
@@ -6236,7 +6231,7 @@ static void haswell_modeset_global_resources(struct drm_device *dev)
                if (!crtc->base.enabled)
                        continue;
 
-               if (crtc->pipe != PIPE_A || crtc->config.pch_pfit.size ||
+               if (crtc->pipe != PIPE_A || crtc->config.pch_pfit.enabled ||
                    crtc->config.cpu_transcoder != TRANSCODER_EDP)
                        enable = true;
        }
@@ -6259,9 +6254,6 @@ static int haswell_crtc_mode_set(struct drm_crtc *crtc,
        if (!intel_ddi_pll_mode_set(crtc))
                return -EINVAL;
 
-       /* Ensure that the cursor is valid for the new mode before changing... */
-       intel_crtc_update_cursor(crtc, true);
-
        if (intel_crtc->config.has_dp_encoder)
                intel_dp_set_m_n(intel_crtc);
 
@@ -6494,15 +6486,15 @@ static void haswell_write_eld(struct drm_connector *connector,
 
        /* Set ELD valid state */
        tmp = I915_READ(aud_cntrl_st2);
-       DRM_DEBUG_DRIVER("HDMI audio: pin eld vld status=0x%8x\n", tmp);
+       DRM_DEBUG_DRIVER("HDMI audio: pin eld vld status=0x%08x\n", tmp);
        tmp |= (AUDIO_ELD_VALID_A << (pipe * 4));
        I915_WRITE(aud_cntrl_st2, tmp);
        tmp = I915_READ(aud_cntrl_st2);
-       DRM_DEBUG_DRIVER("HDMI audio: eld vld status=0x%8x\n", tmp);
+       DRM_DEBUG_DRIVER("HDMI audio: eld vld status=0x%08x\n", tmp);
 
        /* Enable HDMI mode */
        tmp = I915_READ(aud_config);
-       DRM_DEBUG_DRIVER("HDMI audio: audio conf: 0x%8x\n", tmp);
+       DRM_DEBUG_DRIVER("HDMI audio: audio conf: 0x%08x\n", tmp);
        /* clear N_programing_enable and N_value_index */
        tmp &= ~(AUD_CONFIG_N_VALUE_INDEX | AUD_CONFIG_N_PROG_ENABLE);
        I915_WRITE(aud_config, tmp);
@@ -6937,7 +6929,8 @@ 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->cursor_bo != NULL);
+       if (intel_crtc->active)
+               intel_crtc_update_cursor(crtc, intel_crtc->cursor_bo != NULL);
 
        return 0;
 fail_unpin:
@@ -6956,7 +6949,8 @@ 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->cursor_bo != NULL);
+       if (intel_crtc->active)
+               intel_crtc_update_cursor(crtc, intel_crtc->cursor_bo != NULL);
 
        return 0;
 }
@@ -8205,9 +8199,10 @@ static void intel_dump_pipe_config(struct intel_crtc *crtc,
                      pipe_config->gmch_pfit.control,
                      pipe_config->gmch_pfit.pgm_ratios,
                      pipe_config->gmch_pfit.lvds_border_bits);
-       DRM_DEBUG_KMS("pch pfit: pos: 0x%08x, size: 0x%08x\n",
+       DRM_DEBUG_KMS("pch pfit: pos: 0x%08x, size: 0x%08x, %s\n",
                      pipe_config->pch_pfit.pos,
-                     pipe_config->pch_pfit.size);
+                     pipe_config->pch_pfit.size,
+                     pipe_config->pch_pfit.enabled ? "enabled" : "disabled");
        DRM_DEBUG_KMS("ips: %i\n", pipe_config->ips_enabled);
 }
 
@@ -8603,8 +8598,11 @@ intel_pipe_config_compare(struct drm_device *dev,
        if (INTEL_INFO(dev)->gen < 4)
                PIPE_CONF_CHECK_I(gmch_pfit.pgm_ratios);
        PIPE_CONF_CHECK_I(gmch_pfit.lvds_border_bits);
-       PIPE_CONF_CHECK_I(pch_pfit.pos);
-       PIPE_CONF_CHECK_I(pch_pfit.size);
+       PIPE_CONF_CHECK_I(pch_pfit.enabled);
+       if (current_config->pch_pfit.enabled) {
+               PIPE_CONF_CHECK_I(pch_pfit.pos);
+               PIPE_CONF_CHECK_I(pch_pfit.size);
+       }
 
        PIPE_CONF_CHECK_I(ips_enabled);
 
index a47799e832c6e61f5ff02afbf35ebe2cde73a4ed..28cae80495e2b1e9d1f4fe0d089bbd63fd7a11b7 100644 (file)
@@ -280,6 +280,7 @@ struct intel_crtc_config {
        struct {
                u32 pos;
                u32 size;
+               bool enabled;
        } pch_pfit;
 
        /* FDI configuration, only valid if has_pch_encoder is set. */
index 406303b509c1c0afeed4be9379060e5417e212e0..7fa7df546c1ee6e36e119af34d6e79a9d7015e82 100644 (file)
@@ -263,6 +263,8 @@ static bool intel_dvo_compute_config(struct intel_encoder *encoder,
                C(vtotal);
                C(clock);
 #undef C
+
+               drm_mode_set_crtcinfo(adjusted_mode, 0);
        }
 
        if (intel_dvo->dev.dev_ops->mode_fixup)
index 42114ecbae0e3c4c8dc51b7b02a1f658de857873..293564a2896a19038cc87ecba7648bce511388d2 100644 (file)
@@ -112,6 +112,7 @@ intel_pch_panel_fitting(struct intel_crtc *intel_crtc,
 done:
        pipe_config->pch_pfit.pos = (x << 16) | y;
        pipe_config->pch_pfit.size = (width << 16) | height;
+       pipe_config->pch_pfit.enabled = pipe_config->pch_pfit.size != 0;
 }
 
 static void
index 0c115cc4899ffbe00de6ca305d5cd32bd2590405..dd176b7296c1c44904a163cfe82960f6e196249d 100644 (file)
@@ -2096,16 +2096,16 @@ static uint32_t ilk_pipe_pixel_rate(struct drm_device *dev,
                                    struct drm_crtc *crtc)
 {
        struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
-       uint32_t pixel_rate, pfit_size;
+       uint32_t pixel_rate;
 
        pixel_rate = intel_crtc->config.adjusted_mode.clock;
 
        /* We only use IF-ID interlacing. If we ever use PF-ID we'll need to
         * adjust the pixel_rate here. */
 
-       pfit_size = intel_crtc->config.pch_pfit.size;
-       if (pfit_size) {
+       if (intel_crtc->config.pch_pfit.enabled) {
                uint64_t pipe_w, pipe_h, pfit_w, pfit_h;
+               uint32_t pfit_size = intel_crtc->config.pch_pfit.size;
 
                pipe_w = intel_crtc->config.requested_mode.hdisplay;
                pipe_h = intel_crtc->config.requested_mode.vdisplay;
index 85037b9d4934d406306634c486ed93cc92b771f3..49482fd5b76c6cad80298d2d2f67c0050c73a93d 100644 (file)
@@ -788,6 +788,8 @@ static void intel_sdvo_get_dtd_from_mode(struct intel_sdvo_dtd *dtd,
        uint16_t h_sync_offset, v_sync_offset;
        int mode_clock;
 
+       memset(dtd, 0, sizeof(*dtd));
+
        width = mode->hdisplay;
        height = mode->vdisplay;
 
@@ -830,44 +832,51 @@ static void intel_sdvo_get_dtd_from_mode(struct intel_sdvo_dtd *dtd,
        if (mode->flags & DRM_MODE_FLAG_PVSYNC)
                dtd->part2.dtd_flags |= DTD_FLAG_VSYNC_POSITIVE;
 
-       dtd->part2.sdvo_flags = 0;
        dtd->part2.v_sync_off_high = v_sync_offset & 0xc0;
-       dtd->part2.reserved = 0;
 }
 
-static void intel_sdvo_get_mode_from_dtd(struct drm_display_mode * mode,
+static void intel_sdvo_get_mode_from_dtd(struct drm_display_mode *pmode,
                                         const struct intel_sdvo_dtd *dtd)
 {
-       mode->hdisplay = dtd->part1.h_active;
-       mode->hdisplay += ((dtd->part1.h_high >> 4) & 0x0f) << 8;
-       mode->hsync_start = mode->hdisplay + dtd->part2.h_sync_off;
-       mode->hsync_start += (dtd->part2.sync_off_width_high & 0xc0) << 2;
-       mode->hsync_end = mode->hsync_start + dtd->part2.h_sync_width;
-       mode->hsync_end += (dtd->part2.sync_off_width_high & 0x30) << 4;
-       mode->htotal = mode->hdisplay + dtd->part1.h_blank;
-       mode->htotal += (dtd->part1.h_high & 0xf) << 8;
-
-       mode->vdisplay = dtd->part1.v_active;
-       mode->vdisplay += ((dtd->part1.v_high >> 4) & 0x0f) << 8;
-       mode->vsync_start = mode->vdisplay;
-       mode->vsync_start += (dtd->part2.v_sync_off_width >> 4) & 0xf;
-       mode->vsync_start += (dtd->part2.sync_off_width_high & 0x0c) << 2;
-       mode->vsync_start += dtd->part2.v_sync_off_high & 0xc0;
-       mode->vsync_end = mode->vsync_start +
+       struct drm_display_mode mode = {};
+
+       mode.hdisplay = dtd->part1.h_active;
+       mode.hdisplay += ((dtd->part1.h_high >> 4) & 0x0f) << 8;
+       mode.hsync_start = mode.hdisplay + dtd->part2.h_sync_off;
+       mode.hsync_start += (dtd->part2.sync_off_width_high & 0xc0) << 2;
+       mode.hsync_end = mode.hsync_start + dtd->part2.h_sync_width;
+       mode.hsync_end += (dtd->part2.sync_off_width_high & 0x30) << 4;
+       mode.htotal = mode.hdisplay + dtd->part1.h_blank;
+       mode.htotal += (dtd->part1.h_high & 0xf) << 8;
+
+       mode.vdisplay = dtd->part1.v_active;
+       mode.vdisplay += ((dtd->part1.v_high >> 4) & 0x0f) << 8;
+       mode.vsync_start = mode.vdisplay;
+       mode.vsync_start += (dtd->part2.v_sync_off_width >> 4) & 0xf;
+       mode.vsync_start += (dtd->part2.sync_off_width_high & 0x0c) << 2;
+       mode.vsync_start += dtd->part2.v_sync_off_high & 0xc0;
+       mode.vsync_end = mode.vsync_start +
                (dtd->part2.v_sync_off_width & 0xf);
-       mode->vsync_end += (dtd->part2.sync_off_width_high & 0x3) << 4;
-       mode->vtotal = mode->vdisplay + dtd->part1.v_blank;
-       mode->vtotal += (dtd->part1.v_high & 0xf) << 8;
+       mode.vsync_end += (dtd->part2.sync_off_width_high & 0x3) << 4;
+       mode.vtotal = mode.vdisplay + dtd->part1.v_blank;
+       mode.vtotal += (dtd->part1.v_high & 0xf) << 8;
 
-       mode->clock = dtd->part1.clock * 10;
+       mode.clock = dtd->part1.clock * 10;
 
-       mode->flags &= ~(DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC);
        if (dtd->part2.dtd_flags & DTD_FLAG_INTERLACE)
-               mode->flags |= DRM_MODE_FLAG_INTERLACE;
+               mode.flags |= DRM_MODE_FLAG_INTERLACE;
        if (dtd->part2.dtd_flags & DTD_FLAG_HSYNC_POSITIVE)
-               mode->flags |= DRM_MODE_FLAG_PHSYNC;
+               mode.flags |= DRM_MODE_FLAG_PHSYNC;
+       else
+               mode.flags |= DRM_MODE_FLAG_NHSYNC;
        if (dtd->part2.dtd_flags & DTD_FLAG_VSYNC_POSITIVE)
-               mode->flags |= DRM_MODE_FLAG_PVSYNC;
+               mode.flags |= DRM_MODE_FLAG_PVSYNC;
+       else
+               mode.flags |= DRM_MODE_FLAG_NVSYNC;
+
+       drm_mode_set_crtcinfo(&mode, 0);
+
+       drm_mode_copy(pmode, &mode);
 }
 
 static bool intel_sdvo_check_supp_encode(struct intel_sdvo *intel_sdvo)
index a60584763b61dde085f39c8058e4cb6900e2bace..a0b9d8a95b16c17ad6b11ae1b6da662e80484b04 100644 (file)
@@ -124,6 +124,8 @@ void adreno_recover(struct msm_gpu *gpu)
 
        /* reset completed fence seqno, just discard anything pending: */
        adreno_gpu->memptrs->fence = gpu->submitted_fence;
+       adreno_gpu->memptrs->rptr  = 0;
+       adreno_gpu->memptrs->wptr  = 0;
 
        gpu->funcs->pm_resume(gpu);
        ret = gpu->funcs->hw_init(gpu);
@@ -229,7 +231,7 @@ void adreno_idle(struct msm_gpu *gpu)
                        return;
        } while(time_before(jiffies, t));
 
-       DRM_ERROR("timeout waiting for %s to drain ringbuffer!\n", gpu->name);
+       DRM_ERROR("%s: timeout waiting to drain ringbuffer!\n", gpu->name);
 
        /* TODO maybe we need to reset GPU here to recover from hang? */
 }
@@ -256,11 +258,17 @@ void adreno_wait_ring(struct msm_gpu *gpu, uint32_t ndwords)
 {
        struct adreno_gpu *adreno_gpu = to_adreno_gpu(gpu);
        uint32_t freedwords;
+       unsigned long t = jiffies + ADRENO_IDLE_TIMEOUT;
        do {
                uint32_t size = gpu->rb->size / 4;
                uint32_t wptr = get_wptr(gpu->rb);
                uint32_t rptr = adreno_gpu->memptrs->rptr;
                freedwords = (rptr + (size - 1) - wptr) % size;
+
+               if (time_after(jiffies, t)) {
+                       DRM_ERROR("%s: timeout waiting for ringbuffer space\n", gpu->name);
+                       break;
+               }
        } while(freedwords < ndwords);
 }
 
index 864c9773636baf6aa7173c6b16a5f81841a2b922..008d772384c7375859aeb51455f9993156ce9c05 100644 (file)
@@ -499,25 +499,41 @@ int msm_wait_fence_interruptable(struct drm_device *dev, uint32_t fence,
                struct timespec *timeout)
 {
        struct msm_drm_private *priv = dev->dev_private;
-       unsigned long timeout_jiffies = timespec_to_jiffies(timeout);
-       unsigned long start_jiffies = jiffies;
-       unsigned long remaining_jiffies;
        int ret;
 
-       if (time_after(start_jiffies, timeout_jiffies))
-               remaining_jiffies = 0;
-       else
-               remaining_jiffies = timeout_jiffies - start_jiffies;
-
-       ret = wait_event_interruptible_timeout(priv->fence_event,
-                       priv->completed_fence >= fence,
-                       remaining_jiffies);
-       if (ret == 0) {
-               DBG("timeout waiting for fence: %u (completed: %u)",
-                               fence, priv->completed_fence);
-               ret = -ETIMEDOUT;
-       } else if (ret != -ERESTARTSYS) {
-               ret = 0;
+       if (!priv->gpu)
+               return 0;
+
+       if (fence > priv->gpu->submitted_fence) {
+               DRM_ERROR("waiting on invalid fence: %u (of %u)\n",
+                               fence, priv->gpu->submitted_fence);
+               return -EINVAL;
+       }
+
+       if (!timeout) {
+               /* no-wait: */
+               ret = fence_completed(dev, fence) ? 0 : -EBUSY;
+       } else {
+               unsigned long timeout_jiffies = timespec_to_jiffies(timeout);
+               unsigned long start_jiffies = jiffies;
+               unsigned long remaining_jiffies;
+
+               if (time_after(start_jiffies, timeout_jiffies))
+                       remaining_jiffies = 0;
+               else
+                       remaining_jiffies = timeout_jiffies - start_jiffies;
+
+               ret = wait_event_interruptible_timeout(priv->fence_event,
+                               fence_completed(dev, fence),
+                               remaining_jiffies);
+
+               if (ret == 0) {
+                       DBG("timeout waiting for fence: %u (completed: %u)",
+                                       fence, priv->completed_fence);
+                       ret = -ETIMEDOUT;
+               } else if (ret != -ERESTARTSYS) {
+                       ret = 0;
+               }
        }
 
        return ret;
index 80d75094bf0afd9bb24cb34971cd5622259717ca..df8f1d084bc1d76d1ee8dc5db948e7ebf9f87771 100644 (file)
@@ -153,7 +153,7 @@ void *msm_gem_vaddr(struct drm_gem_object *obj);
 int msm_gem_queue_inactive_work(struct drm_gem_object *obj,
                struct work_struct *work);
 void msm_gem_move_to_active(struct drm_gem_object *obj,
-               struct msm_gpu *gpu, uint32_t fence);
+               struct msm_gpu *gpu, bool write, uint32_t fence);
 void msm_gem_move_to_inactive(struct drm_gem_object *obj);
 int msm_gem_cpu_prep(struct drm_gem_object *obj, uint32_t op,
                struct timespec *timeout);
@@ -191,6 +191,12 @@ u32 msm_readl(const void __iomem *addr);
 #define DBG(fmt, ...) DRM_DEBUG(fmt"\n", ##__VA_ARGS__)
 #define VERB(fmt, ...) if (0) DRM_DEBUG(fmt"\n", ##__VA_ARGS__)
 
+static inline bool fence_completed(struct drm_device *dev, uint32_t fence)
+{
+       struct msm_drm_private *priv = dev->dev_private;
+       return priv->completed_fence >= fence;
+}
+
 static inline int align_pitch(int width, int bpp)
 {
        int bytespp = (bpp + 7) / 8;
index 6b5a6c8c7658c5b91e905ac013779d022d299cfe..29eacfa29cfb6952c38b89d8e51883890d9125f2 100644 (file)
@@ -40,9 +40,9 @@ static struct page **get_pages(struct drm_gem_object *obj)
                }
 
                msm_obj->sgt = drm_prime_pages_to_sg(p, npages);
-               if (!msm_obj->sgt) {
+               if (IS_ERR(msm_obj->sgt)) {
                        dev_err(dev->dev, "failed to allocate sgt\n");
-                       return ERR_PTR(-ENOMEM);
+                       return ERR_CAST(msm_obj->sgt);
                }
 
                msm_obj->pages = p;
@@ -159,7 +159,6 @@ out_unlock:
 out:
        switch (ret) {
        case -EAGAIN:
-               set_need_resched();
        case 0:
        case -ERESTARTSYS:
        case -EINTR:
@@ -393,11 +392,14 @@ int msm_gem_queue_inactive_work(struct drm_gem_object *obj,
 }
 
 void msm_gem_move_to_active(struct drm_gem_object *obj,
-               struct msm_gpu *gpu, uint32_t fence)
+               struct msm_gpu *gpu, bool write, uint32_t fence)
 {
        struct msm_gem_object *msm_obj = to_msm_bo(obj);
        msm_obj->gpu = gpu;
-       msm_obj->fence = fence;
+       if (write)
+               msm_obj->write_fence = fence;
+       else
+               msm_obj->read_fence = fence;
        list_del_init(&msm_obj->mm_list);
        list_add_tail(&msm_obj->mm_list, &gpu->active_list);
 }
@@ -411,7 +413,8 @@ void msm_gem_move_to_inactive(struct drm_gem_object *obj)
        WARN_ON(!mutex_is_locked(&dev->struct_mutex));
 
        msm_obj->gpu = NULL;
-       msm_obj->fence = 0;
+       msm_obj->read_fence = 0;
+       msm_obj->write_fence = 0;
        list_del_init(&msm_obj->mm_list);
        list_add_tail(&msm_obj->mm_list, &priv->inactive_list);
 
@@ -433,8 +436,18 @@ int msm_gem_cpu_prep(struct drm_gem_object *obj, uint32_t op,
        struct msm_gem_object *msm_obj = to_msm_bo(obj);
        int ret = 0;
 
-       if (is_active(msm_obj) && !(op & MSM_PREP_NOSYNC))
-               ret = msm_wait_fence_interruptable(dev, msm_obj->fence, timeout);
+       if (is_active(msm_obj)) {
+               uint32_t fence = 0;
+
+               if (op & MSM_PREP_READ)
+                       fence = msm_obj->write_fence;
+               if (op & MSM_PREP_WRITE)
+                       fence = max(fence, msm_obj->read_fence);
+               if (op & MSM_PREP_NOSYNC)
+                       timeout = NULL;
+
+               ret = msm_wait_fence_interruptable(dev, fence, timeout);
+       }
 
        /* TODO cache maintenance */
 
@@ -455,9 +468,10 @@ void msm_gem_describe(struct drm_gem_object *obj, struct seq_file *m)
        uint64_t off = drm_vma_node_start(&obj->vma_node);
 
        WARN_ON(!mutex_is_locked(&dev->struct_mutex));
-       seq_printf(m, "%08x: %c(%d) %2d (%2d) %08llx %p %d\n",
+       seq_printf(m, "%08x: %c(r=%u,w=%u) %2d (%2d) %08llx %p %d\n",
                        msm_obj->flags, is_active(msm_obj) ? 'A' : 'I',
-                       msm_obj->fence, obj->name, obj->refcount.refcount.counter,
+                       msm_obj->read_fence, msm_obj->write_fence,
+                       obj->name, obj->refcount.refcount.counter,
                        off, msm_obj->vaddr, obj->size);
 }
 
index d746f13d283c8cdaf7d885b2cd52e254a98f6061..0676f32e2c6ab917fe9980380c82137a1ad8f7ce 100644 (file)
@@ -36,7 +36,7 @@ struct msm_gem_object {
         */
        struct list_head mm_list;
        struct msm_gpu *gpu;     /* non-null if active */
-       uint32_t fence;
+       uint32_t read_fence, write_fence;
 
        /* Transiently in the process of submit ioctl, objects associated
         * with the submit are on submit->bo_list.. this only lasts for
index 3e1ef3a00f60cc929555768c1cb963b0b265e251..5281d4bc37f750e2162e4bd1f17859e4921c45cc 100644 (file)
@@ -78,7 +78,7 @@ static int submit_lookup_objects(struct msm_gem_submit *submit,
                }
 
                if (submit_bo.flags & BO_INVALID_FLAGS) {
-                       DBG("invalid flags: %x", submit_bo.flags);
+                       DRM_ERROR("invalid flags: %x\n", submit_bo.flags);
                        ret = -EINVAL;
                        goto out_unlock;
                }
@@ -92,7 +92,7 @@ static int submit_lookup_objects(struct msm_gem_submit *submit,
                 */
                obj = idr_find(&file->object_idr, submit_bo.handle);
                if (!obj) {
-                       DBG("invalid handle %u at index %u", submit_bo.handle, i);
+                       DRM_ERROR("invalid handle %u at index %u\n", submit_bo.handle, i);
                        ret = -EINVAL;
                        goto out_unlock;
                }
@@ -100,7 +100,7 @@ static int submit_lookup_objects(struct msm_gem_submit *submit,
                msm_obj = to_msm_bo(obj);
 
                if (!list_empty(&msm_obj->submit_entry)) {
-                       DBG("handle %u at index %u already on submit list",
+                       DRM_ERROR("handle %u at index %u already on submit list\n",
                                        submit_bo.handle, i);
                        ret = -EINVAL;
                        goto out_unlock;
@@ -216,8 +216,9 @@ static int submit_bo(struct msm_gem_submit *submit, uint32_t idx,
                struct msm_gem_object **obj, uint32_t *iova, bool *valid)
 {
        if (idx >= submit->nr_bos) {
-               DBG("invalid buffer index: %u (out of %u)", idx, submit->nr_bos);
-               return EINVAL;
+               DRM_ERROR("invalid buffer index: %u (out of %u)\n",
+                               idx, submit->nr_bos);
+               return -EINVAL;
        }
 
        if (obj)
@@ -239,7 +240,7 @@ static int submit_reloc(struct msm_gem_submit *submit, struct msm_gem_object *ob
        int ret;
 
        if (offset % 4) {
-               DBG("non-aligned cmdstream buffer: %u", offset);
+               DRM_ERROR("non-aligned cmdstream buffer: %u\n", offset);
                return -EINVAL;
        }
 
@@ -266,7 +267,7 @@ static int submit_reloc(struct msm_gem_submit *submit, struct msm_gem_object *ob
                        return -EFAULT;
 
                if (submit_reloc.submit_offset % 4) {
-                       DBG("non-aligned reloc offset: %u",
+                       DRM_ERROR("non-aligned reloc offset: %u\n",
                                        submit_reloc.submit_offset);
                        return -EINVAL;
                }
@@ -276,7 +277,7 @@ static int submit_reloc(struct msm_gem_submit *submit, struct msm_gem_object *ob
 
                if ((off >= (obj->base.size / 4)) ||
                                (off < last_offset)) {
-                       DBG("invalid offset %u at reloc %u", off, i);
+                       DRM_ERROR("invalid offset %u at reloc %u\n", off, i);
                        return -EINVAL;
                }
 
@@ -374,14 +375,15 @@ int msm_ioctl_gem_submit(struct drm_device *dev, void *data,
                        goto out;
 
                if (submit_cmd.size % 4) {
-                       DBG("non-aligned cmdstream buffer size: %u",
+                       DRM_ERROR("non-aligned cmdstream buffer size: %u\n",
                                        submit_cmd.size);
                        ret = -EINVAL;
                        goto out;
                }
 
-               if (submit_cmd.size >= msm_obj->base.size) {
-                       DBG("invalid cmdstream size: %u", submit_cmd.size);
+               if ((submit_cmd.size + submit_cmd.submit_offset) >=
+                               msm_obj->base.size) {
+                       DRM_ERROR("invalid cmdstream size: %u\n", submit_cmd.size);
                        ret = -EINVAL;
                        goto out;
                }
index e1e1ec9321ffe5d8db74e53a5d52b8a4122a51d9..3bab937965d1f596405864676464fe6370bf87bd 100644 (file)
 static void bs_init(struct msm_gpu *gpu, struct platform_device *pdev)
 {
        struct drm_device *dev = gpu->dev;
-       struct kgsl_device_platform_data *pdata = pdev->dev.platform_data;
+       struct kgsl_device_platform_data *pdata;
 
        if (!pdev) {
                dev_err(dev->dev, "could not find dtv pdata\n");
                return;
        }
 
+       pdata = pdev->dev.platform_data;
        if (pdata->bus_scale_table) {
                gpu->bsc = msm_bus_scale_register_client(pdata->bus_scale_table);
                DBG("bus scale client: %08x", gpu->bsc);
@@ -230,6 +231,8 @@ static void hangcheck_timer_reset(struct msm_gpu *gpu)
 static void hangcheck_handler(unsigned long data)
 {
        struct msm_gpu *gpu = (struct msm_gpu *)data;
+       struct drm_device *dev = gpu->dev;
+       struct msm_drm_private *priv = dev->dev_private;
        uint32_t fence = gpu->funcs->last_fence(gpu);
 
        if (fence != gpu->hangcheck_fence) {
@@ -237,14 +240,22 @@ static void hangcheck_handler(unsigned long data)
                gpu->hangcheck_fence = fence;
        } else if (fence < gpu->submitted_fence) {
                /* no progress and not done.. hung! */
-               struct msm_drm_private *priv = gpu->dev->dev_private;
                gpu->hangcheck_fence = fence;
+               dev_err(dev->dev, "%s: hangcheck detected gpu lockup!\n",
+                               gpu->name);
+               dev_err(dev->dev, "%s:     completed fence: %u\n",
+                               gpu->name, fence);
+               dev_err(dev->dev, "%s:     submitted fence: %u\n",
+                               gpu->name, gpu->submitted_fence);
                queue_work(priv->wq, &gpu->recover_work);
        }
 
        /* if still more pending work, reset the hangcheck timer: */
        if (gpu->submitted_fence > gpu->hangcheck_fence)
                hangcheck_timer_reset(gpu);
+
+       /* workaround for missing irq: */
+       queue_work(priv->wq, &gpu->retire_work);
 }
 
 /*
@@ -265,7 +276,8 @@ static void retire_worker(struct work_struct *work)
                obj = list_first_entry(&gpu->active_list,
                                struct msm_gem_object, mm_list);
 
-               if (obj->fence <= fence) {
+               if ((obj->read_fence <= fence) &&
+                               (obj->write_fence <= fence)) {
                        /* move to inactive: */
                        msm_gem_move_to_inactive(&obj->base);
                        msm_gem_put_iova(&obj->base, gpu->id);
@@ -321,7 +333,11 @@ int msm_gpu_submit(struct msm_gpu *gpu, struct msm_gem_submit *submit,
                                        submit->gpu->id, &iova);
                }
 
-               msm_gem_move_to_active(&msm_obj->base, gpu, submit->fence);
+               if (submit->bos[i].flags & MSM_SUBMIT_BO_READ)
+                       msm_gem_move_to_active(&msm_obj->base, gpu, false, submit->fence);
+
+               if (submit->bos[i].flags & MSM_SUBMIT_BO_WRITE)
+                       msm_gem_move_to_active(&msm_obj->base, gpu, true, submit->fence);
        }
        hangcheck_timer_reset(gpu);
        mutex_unlock(&dev->struct_mutex);
index 290734191f72d85a855022a2f0e24e7a6c895ffb..b46fb45f2cca4a5881b64d93577e6ae03a221670 100644 (file)
@@ -1322,10 +1322,9 @@ extern int drm_newctx(struct drm_device *dev, void *data,
 extern int drm_rmctx(struct drm_device *dev, void *data,
                     struct drm_file *file_priv);
 
-extern void drm_legacy_ctxbitmap_init(struct drm_device *dev);
-extern void drm_legacy_ctxbitmap_cleanup(struct drm_device *dev);
-extern void drm_legacy_ctxbitmap_release(struct drm_device *dev,
-                                        struct drm_file *file_priv);
+extern int drm_ctxbitmap_init(struct drm_device *dev);
+extern void drm_ctxbitmap_cleanup(struct drm_device *dev);
+extern void drm_ctxbitmap_free(struct drm_device *dev, int ctx_handle);
 
 extern int drm_setsareactx(struct drm_device *dev, void *data,
                           struct drm_file *file_priv);