Merge branch 'drm-intel-fixes' of git://people.freedesktop.org/~danvet/drm-intel...
authorDave Airlie <airlied@redhat.com>
Sun, 7 Oct 2012 11:13:54 +0000 (21:13 +1000)
committerDave Airlie <airlied@redhat.com>
Sun, 7 Oct 2012 11:13:54 +0000 (21:13 +1000)
Daniel writes:

Bigger -fixes pile, mostly because I've included Ajax' DP dongle stuff,
as discussed on irc. Otherwise just small things:
- regression fix to finally make 6bpc auto-dither on dp work (Jani)
- reinstate an snb ctx w/a that accidentally got lost in a rework (Chris)
- fixup the DP train sequence, logic-goof-up uncovered by Coverty (Chris)
- fix set_caching locking (Ben)
- fix spurious segfault on con-current gtt mmap faulting (Dimitry and Mika)
- some pageflip correctness fixes (still hunting down some issues, but
  these are the worst offenders of confused code that we've tracked down
  thus far) from Chris and me
- fixup swizzling settings on vlv (Jesse)
- gt_mode w/a from Ben added, fixes snb gt1 rc6+hw ctx hangs.

* 'drm-intel-fixes' of git://people.freedesktop.org/~danvet/drm-intel:
  drm/i915: Fix GT_MODE default value
  drm/i915: don't frob the vblank ts in finish_page_flip
  drm/i915: call drm_handle_vblank before finish_page_flip
  drm/i915: print warning if vmi915_gem_fault error is not handled
  drm/i915: EBUSY status handling added to i915_gem_fault().
  drm/i915: Try harder to complete DP training pattern 1
  drm/i915: set swizzling to none on VLV
  drm/dp: Make sink count DP 1.2 aware
  drm/dp: Document DP spec versions for various DPCD registers
  drm/i915/dp: Be smarter about connection sense for branch devices
  drm/i915/dp: Fetch downstream port info if needed during DPCD fetch
  drm/dp: Update DPCD defines
  drm: Export drm_probe_ddc()
  drm/i915: Flush the pending flips on the CRTC before modification
  drm/i915: Actually invalidate the TLB for the SandyBridge HW contexts w/a
  drm/i915: Fix set_caching locking
  drm/i915: use adjusted_mode instead of mode for checking the 6bpc force flag

1  2 
drivers/gpu/drm/drm_edid.c
drivers/gpu/drm/i915/i915_gem.c
drivers/gpu/drm/i915/i915_gem_context.c
drivers/gpu/drm/i915/i915_gem_tiling.c
drivers/gpu/drm/i915/i915_irq.c
drivers/gpu/drm/i915/intel_display.c
drivers/gpu/drm/i915/intel_dp.c
drivers/gpu/drm/i915/intel_drv.h
include/drm/drm_crtc.h

@@@ -31,8 -31,8 +31,8 @@@
  #include <linux/slab.h>
  #include <linux/i2c.h>
  #include <linux/module.h>
 -#include "drmP.h"
 -#include "drm_edid.h"
 +#include <drm/drmP.h>
 +#include <drm/drm_edid.h>
  #include "drm_edid_modes.h"
  
  #define version_greater(edid, maj, min) \
@@@ -395,13 -395,14 +395,14 @@@ out
   * \param adapter : i2c device adaptor
   * \return 1 on success
   */
static bool
+ bool
  drm_probe_ddc(struct i2c_adapter *adapter)
  {
        unsigned char out;
  
        return (drm_do_probe_ddc_edid(adapter, &out, 0, 1) == 0);
  }
+ EXPORT_SYMBOL(drm_probe_ddc);
  
  /**
   * drm_get_edid - get EDID data, if available
@@@ -25,8 -25,9 +25,8 @@@
   *
   */
  
 -#include "drmP.h"
 -#include "drm.h"
 -#include "i915_drm.h"
 +#include <drm/drmP.h>
 +#include <drm/i915_drm.h>
  #include "i915_drv.h"
  #include "i915_trace.h"
  #include "intel_drv.h"
        case 0:
        case -ERESTARTSYS:
        case -EINTR:
+       case -EBUSY:
+               /*
+                * EBUSY is ok: this just means that another thread
+                * already did the job.
+                */
                return VM_FAULT_NOPAGE;
        case -ENOMEM:
                return VM_FAULT_OOM;
        default:
+               WARN_ON_ONCE(ret);
                return VM_FAULT_SIGBUS;
        }
  }
@@@ -3217,10 -3224,6 +3223,6 @@@ int i915_gem_set_caching_ioctl(struct d
        enum i915_cache_level level;
        int ret;
  
-       ret = i915_mutex_lock_interruptible(dev);
-       if (ret)
-               return ret;
        switch (args->caching) {
        case I915_CACHING_NONE:
                level = I915_CACHE_NONE;
                return -EINVAL;
        }
  
+       ret = i915_mutex_lock_interruptible(dev);
+       if (ret)
+               return ret;
        obj = to_intel_bo(drm_gem_object_lookup(dev, file, args->handle));
        if (&obj->base == NULL) {
                ret = -ENOENT;
@@@ -85,8 -85,8 +85,8 @@@
   *
   */
  
 -#include "drmP.h"
 -#include "i915_drm.h"
 +#include <drm/drmP.h>
 +#include <drm/i915_drm.h>
  #include "i915_drv.h"
  
  /* This is a HW constraint. The value below is the largest known requirement
@@@ -328,7 -328,7 +328,7 @@@ mi_set_context(struct intel_ring_buffe
         * itlb_before_ctx_switch.
         */
        if (IS_GEN6(ring->dev) && ring->itlb_before_ctx_switch) {
-               ret = ring->flush(ring, 0, 0);
+               ret = ring->flush(ring, I915_GEM_GPU_DOMAINS, 0);
                if (ret)
                        return ret;
        }
   *
   */
  
 -#include "linux/string.h"
 -#include "linux/bitops.h"
 -#include "drmP.h"
 -#include "drm.h"
 -#include "i915_drm.h"
 +#include <linux/string.h>
 +#include <linux/bitops.h>
 +#include <drm/drmP.h>
 +#include <drm/i915_drm.h>
  #include "i915_drv.h"
  
  /** @file i915_gem_tiling.c
@@@ -91,7 -92,10 +91,10 @@@ i915_gem_detect_bit_6_swizzle(struct dr
        uint32_t swizzle_x = I915_BIT_6_SWIZZLE_UNKNOWN;
        uint32_t swizzle_y = I915_BIT_6_SWIZZLE_UNKNOWN;
  
-       if (INTEL_INFO(dev)->gen >= 6) {
+       if (IS_VALLEYVIEW(dev)) {
+               swizzle_x = I915_BIT_6_SWIZZLE_NONE;
+               swizzle_y = I915_BIT_6_SWIZZLE_NONE;
+       } else if (INTEL_INFO(dev)->gen >= 6) {
                uint32_t dimm_c0, dimm_c1;
                dimm_c0 = I915_READ(MAD_DIMM_C0);
                dimm_c1 = I915_READ(MAD_DIMM_C1);
@@@ -30,8 -30,9 +30,8 @@@
  
  #include <linux/sysrq.h>
  #include <linux/slab.h>
 -#include "drmP.h"
 -#include "drm.h"
 -#include "i915_drm.h"
 +#include <drm/drmP.h>
 +#include <drm/i915_drm.h>
  #include "i915_drv.h"
  #include "i915_trace.h"
  #include "intel_drv.h"
@@@ -697,12 -698,12 +697,12 @@@ static irqreturn_t ivybridge_irq_handle
                        intel_opregion_gse_intr(dev);
  
                for (i = 0; i < 3; i++) {
+                       if (de_iir & (DE_PIPEA_VBLANK_IVB << (5 * i)))
+                               drm_handle_vblank(dev, i);
                        if (de_iir & (DE_PLANEA_FLIP_DONE_IVB << (5 * i))) {
                                intel_prepare_page_flip(dev, i);
                                intel_finish_page_flip_plane(dev, i);
                        }
-                       if (de_iir & (DE_PIPEA_VBLANK_IVB << (5 * i)))
-                               drm_handle_vblank(dev, i);
                }
  
                /* check event from PCH */
@@@ -784,6 -785,12 +784,12 @@@ static irqreturn_t ironlake_irq_handler
        if (de_iir & DE_GSE)
                intel_opregion_gse_intr(dev);
  
+       if (de_iir & DE_PIPEA_VBLANK)
+               drm_handle_vblank(dev, 0);
+       if (de_iir & DE_PIPEB_VBLANK)
+               drm_handle_vblank(dev, 1);
        if (de_iir & DE_PLANEA_FLIP_DONE) {
                intel_prepare_page_flip(dev, 0);
                intel_finish_page_flip_plane(dev, 0);
                intel_finish_page_flip_plane(dev, 1);
        }
  
-       if (de_iir & DE_PIPEA_VBLANK)
-               drm_handle_vblank(dev, 0);
-       if (de_iir & DE_PIPEB_VBLANK)
-               drm_handle_vblank(dev, 1);
        /* check event from PCH */
        if (de_iir & DE_PCH_EVENT) {
                if (pch_iir & hotplug_mask)
  #include <linux/slab.h>
  #include <linux/vgaarb.h>
  #include <drm/drm_edid.h>
 -#include "drmP.h"
 +#include <drm/drmP.h>
  #include "intel_drv.h"
 -#include "i915_drm.h"
 +#include <drm/i915_drm.h>
  #include "i915_drv.h"
  #include "i915_trace.h"
 -#include "drm_dp_helper.h"
 -#include "drm_crtc_helper.h"
 +#include <drm/drm_dp_helper.h>
 +#include <drm/drm_crtc_helper.h>
  #include <linux/dma_remapping.h>
  
  #define HAS_eDP (intel_pipe_has_type(crtc, INTEL_OUTPUT_EDP))
@@@ -2806,13 -2806,34 +2806,34 @@@ static void ironlake_fdi_disable(struc
        udelay(100);
  }
  
+ static bool intel_crtc_has_pending_flip(struct drm_crtc *crtc)
+ {
+       struct drm_device *dev = crtc->dev;
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       unsigned long flags;
+       bool pending;
+       if (atomic_read(&dev_priv->mm.wedged))
+               return false;
+       spin_lock_irqsave(&dev->event_lock, flags);
+       pending = to_intel_crtc(crtc)->unpin_work != NULL;
+       spin_unlock_irqrestore(&dev->event_lock, flags);
+       return pending;
+ }
  static void intel_crtc_wait_for_pending_flips(struct drm_crtc *crtc)
  {
        struct drm_device *dev = crtc->dev;
+       struct drm_i915_private *dev_priv = dev->dev_private;
  
        if (crtc->fb == NULL)
                return;
  
+       wait_event(dev_priv->pending_flip_queue,
+                  !intel_crtc_has_pending_flip(crtc));
        mutex_lock(&dev->struct_mutex);
        intel_finish_fb(crtc->fb);
        mutex_unlock(&dev->struct_mutex);
@@@ -4370,7 -4391,7 +4391,7 @@@ static int i9xx_crtc_mode_set(struct dr
        /* default to 8bpc */
        pipeconf &= ~(PIPECONF_BPP_MASK | PIPECONF_DITHER_EN);
        if (is_dp) {
-               if (mode->private_flags & INTEL_MODE_DP_FORCE_6BPC) {
+               if (adjusted_mode->private_flags & INTEL_MODE_DP_FORCE_6BPC) {
                        pipeconf |= PIPECONF_BPP_6 |
                                    PIPECONF_DITHER_EN |
                                    PIPECONF_DITHER_TYPE_SP;
@@@ -4802,7 -4823,8 +4823,8 @@@ static int ironlake_crtc_mode_set(struc
                target_clock = adjusted_mode->clock;
  
        /* determine panel color depth */
-       dither = intel_choose_pipe_bpp_dither(crtc, fb, &pipe_bpp, mode);
+       dither = intel_choose_pipe_bpp_dither(crtc, fb, &pipe_bpp,
+                                             adjusted_mode);
        if (is_lvds && dev_priv->lvds_dither)
                dither = true;
  
@@@ -6159,15 -6181,13 +6181,13 @@@ static void do_intel_finish_page_flip(s
        struct intel_unpin_work *work;
        struct drm_i915_gem_object *obj;
        struct drm_pending_vblank_event *e;
-       struct timeval tnow, tvbl;
+       struct timeval tvbl;
        unsigned long flags;
  
        /* Ignore early vblank irqs */
        if (intel_crtc == NULL)
                return;
  
-       do_gettimeofday(&tnow);
        spin_lock_irqsave(&dev->event_lock, flags);
        work = intel_crtc->unpin_work;
        if (work == NULL || !work->pending) {
                e = work->event;
                e->event.sequence = drm_vblank_count_and_time(dev, intel_crtc->pipe, &tvbl);
  
-               /* Called before vblank count and timestamps have
-                * been updated for the vblank interval of flip
-                * completion? Need to increment vblank count and
-                * add one videorefresh duration to returned timestamp
-                * to account for this. We assume this happened if we
-                * get called over 0.9 frame durations after the last
-                * timestamped vblank.
-                *
-                * This calculation can not be used with vrefresh rates
-                * below 5Hz (10Hz to be on the safe side) without
-                * promoting to 64 integers.
-                */
-               if (10 * (timeval_to_ns(&tnow) - timeval_to_ns(&tvbl)) >
-                   9 * crtc->framedur_ns) {
-                       e->event.sequence++;
-                       tvbl = ns_to_timeval(timeval_to_ns(&tvbl) +
-                                            crtc->framedur_ns);
-               }
                e->event.tv_sec = tvbl.tv_sec;
                e->event.tv_usec = tvbl.tv_usec;
  
  
        atomic_clear_mask(1 << intel_crtc->plane,
                          &obj->pending_flip.counter);
-       if (atomic_read(&obj->pending_flip) == 0)
-               wake_up(&dev_priv->pending_flip_queue);
  
+       wake_up(&dev_priv->pending_flip_queue);
        schedule_work(&work->work);
  
        trace_i915_flip_complete(intel_crtc->plane, work->pending_flip_obj);
  #include <linux/i2c.h>
  #include <linux/slab.h>
  #include <linux/export.h>
 -#include "drmP.h"
 -#include "drm.h"
 -#include "drm_crtc.h"
 -#include "drm_crtc_helper.h"
 -#include "drm_edid.h"
 +#include <drm/drmP.h>
 +#include <drm/drm_crtc.h>
 +#include <drm/drm_crtc_helper.h>
 +#include <drm/drm_edid.h>
  #include "intel_drv.h"
 -#include "i915_drm.h"
 +#include <drm/i915_drm.h>
  #include "i915_drv.h"
  
+ #define DP_RECEIVER_CAP_SIZE  0xf
  #define DP_LINK_STATUS_SIZE   6
  #define DP_LINK_CHECK_TIMEOUT (10 * 1000)
  
@@@ -1796,8 -1798,7 +1797,7 @@@ intel_dp_start_link_train(struct intel_
                        if ((intel_dp->train_set[i] & DP_TRAIN_MAX_SWING_REACHED) == 0)
                                break;
                if (i == intel_dp->lane_count && voltage_tries == 5) {
-                       ++loop_tries;
-                       if (loop_tries == 5) {
+                       if (++loop_tries == 5) {
                                DRM_DEBUG_KMS("too many full retries, give up\n");
                                break;
                        }
                }
  
                /* Check to see if we've tried the same voltage 5 times */
-               if ((intel_dp->train_set[0] & DP_TRAIN_VOLTAGE_SWING_MASK) == voltage) {
-                       ++voltage_tries;
-                       if (voltage_tries == 5) {
-                               DRM_DEBUG_KMS("too many voltage retries, give up\n");
-                               break;
-                       }
-               } else
+               if ((intel_dp->train_set[0] & DP_TRAIN_VOLTAGE_SWING_MASK) != voltage) {
+                       voltage = intel_dp->train_set[0] & DP_TRAIN_VOLTAGE_SWING_MASK;
                        voltage_tries = 0;
-               voltage = intel_dp->train_set[0] & DP_TRAIN_VOLTAGE_SWING_MASK;
+               } else
+                       ++voltage_tries;
  
                /* Compute new intel_dp->train_set as requested by target */
                intel_get_adjust_train(intel_dp, link_status);
@@@ -1963,12 -1960,25 +1959,25 @@@ static boo
  intel_dp_get_dpcd(struct intel_dp *intel_dp)
  {
        if (intel_dp_aux_native_read_retry(intel_dp, 0x000, intel_dp->dpcd,
-                                          sizeof(intel_dp->dpcd)) &&
-           (intel_dp->dpcd[DP_DPCD_REV] != 0)) {
-               return true;
-       }
+                                          sizeof(intel_dp->dpcd)) == 0)
+               return false; /* aux transfer failed */
  
-       return false;
+       if (intel_dp->dpcd[DP_DPCD_REV] == 0)
+               return false; /* DPCD not present */
+       if (!(intel_dp->dpcd[DP_DOWNSTREAMPORT_PRESENT] &
+             DP_DWN_STRM_PORT_PRESENT))
+               return true; /* native DP sink */
+       if (intel_dp->dpcd[DP_DPCD_REV] == 0x10)
+               return true; /* no per-port downstream info */
+       if (intel_dp_aux_native_read_retry(intel_dp, DP_DOWNSTREAM_PORT_0,
+                                          intel_dp->downstream_ports,
+                                          DP_MAX_DOWNSTREAM_PORTS) == 0)
+               return false; /* downstream port status fetch failed */
+       return true;
  }
  
  static void
@@@ -2068,11 -2078,43 +2077,43 @@@ intel_dp_check_link_status(struct intel
        }
  }
  
+ /* XXX this is probably wrong for multiple downstream ports */
  static enum drm_connector_status
  intel_dp_detect_dpcd(struct intel_dp *intel_dp)
  {
-       if (intel_dp_get_dpcd(intel_dp))
+       uint8_t *dpcd = intel_dp->dpcd;
+       bool hpd;
+       uint8_t type;
+       if (!intel_dp_get_dpcd(intel_dp))
+               return connector_status_disconnected;
+       /* if there's no downstream port, we're done */
+       if (!(dpcd[DP_DOWNSTREAMPORT_PRESENT] & DP_DWN_STRM_PORT_PRESENT))
                return connector_status_connected;
+       /* If we're HPD-aware, SINK_COUNT changes dynamically */
+       hpd = !!(intel_dp->downstream_ports[0] & DP_DS_PORT_HPD);
+       if (hpd) {
+               uint8_t reg;
+               if (!intel_dp_aux_native_read_retry(intel_dp, DP_SINK_COUNT,
+                                                   &reg, 1))
+                       return connector_status_unknown;
+               return DP_GET_SINK_COUNT(reg) ? connector_status_connected
+                                             : connector_status_disconnected;
+       }
+       /* If no HPD, poke DDC gently */
+       if (drm_probe_ddc(&intel_dp->adapter))
+               return connector_status_connected;
+       /* Well we tried, say unknown for unreliable port types */
+       type = intel_dp->downstream_ports[0] & DP_DS_PORT_TYPE_MASK;
+       if (type == DP_DS_PORT_TYPE_VGA || type == DP_DS_PORT_TYPE_NON_EDID)
+               return connector_status_unknown;
+       /* Anything else is out of spec, warn and ignore */
+       DRM_DEBUG_KMS("Broken DP branch device, ignoring\n");
        return connector_status_disconnected;
  }
  
  #define __INTEL_DRV_H__
  
  #include <linux/i2c.h>
 -#include "i915_drm.h"
 +#include <drm/i915_drm.h>
  #include "i915_drv.h"
 -#include "drm_crtc.h"
 -#include "drm_crtc_helper.h"
 -#include "drm_fb_helper.h"
 -#include "drm_dp_helper.h"
 +#include <drm/drm_crtc.h>
 +#include <drm/drm_crtc_helper.h>
 +#include <drm/drm_fb_helper.h>
 +#include <drm/drm_dp_helper.h>
  
  #define _wait_for(COND, MS, W) ({ \
        unsigned long timeout__ = jiffies + msecs_to_jiffies(MS);       \
@@@ -332,6 -332,7 +332,7 @@@ struct intel_hdmi 
  };
  
  #define DP_RECEIVER_CAP_SIZE          0xf
+ #define DP_MAX_DOWNSTREAM_PORTS               0x10
  #define DP_LINK_CONFIGURATION_SIZE    9
  
  struct intel_dp {
        uint8_t link_bw;
        uint8_t lane_count;
        uint8_t dpcd[DP_RECEIVER_CAP_SIZE];
+       uint8_t downstream_ports[DP_MAX_DOWNSTREAM_PORTS];
        struct i2c_adapter adapter;
        struct i2c_algo_dp_aux_data algo;
        bool is_pch_edp;
diff --combined include/drm/drm_crtc.h
@@@ -30,7 -30,6 +30,7 @@@
  #include <linux/types.h>
  #include <linux/idr.h>
  #include <linux/fb.h>
 +#include <drm/drm_mode.h>
  
  #include <drm/drm_fourcc.h>
  
@@@ -219,7 -218,6 +219,7 @@@ struct drm_display_info 
  };
  
  struct drm_framebuffer_funcs {
 +      /* note: use drm_framebuffer_remove() */
        void (*destroy)(struct drm_framebuffer *framebuffer);
        int (*create_handle)(struct drm_framebuffer *fb,
                             struct drm_file *file_priv,
  
  struct drm_framebuffer {
        struct drm_device *dev;
 +      /*
 +       * Note that the fb is refcounted for the benefit of driver internals,
 +       * for example some hw, disabling a CRTC/plane is asynchronous, and
 +       * scanout does not actually complete until the next vblank.  So some
 +       * cleanup (like releasing the reference(s) on the backing GEM bo(s))
 +       * should be deferred.  In cases like this, the driver would like to
 +       * hold a ref to the fb even though it has already been removed from
 +       * userspace perspective.
 +       */
 +      struct kref refcount;
        struct list_head head;
        struct drm_mode_object base;
        const struct drm_framebuffer_funcs *funcs;
@@@ -369,9 -357,6 +369,9 @@@ struct drm_crtc_funcs 
   * @enabled: is this CRTC enabled?
   * @mode: current mode timings
   * @hwmode: mode timings as programmed to hw regs
 + * @invert_dimensions: for purposes of error checking crtc vs fb sizes,
 + *    invert the width/height of the crtc.  This is used if the driver
 + *    is performing 90 or 270 degree rotated scanout
   * @x: x position on screen
   * @y: y position on screen
   * @funcs: CRTC control functions
@@@ -405,8 -390,6 +405,8 @@@ struct drm_crtc 
         */
        struct drm_display_mode hwmode;
  
 +      bool invert_dimensions;
 +
        int x, y;
        const struct drm_crtc_funcs *funcs;
  
@@@ -878,6 -861,7 +878,7 @@@ extern char *drm_get_tv_subconnector_na
  extern char *drm_get_tv_select_name(int val);
  extern void drm_fb_release(struct drm_file *file_priv);
  extern int drm_mode_group_init_legacy_group(struct drm_device *dev, struct drm_mode_group *group);
+ extern bool drm_probe_ddc(struct i2c_adapter *adapter);
  extern struct edid *drm_get_edid(struct drm_connector *connector,
                                 struct i2c_adapter *adapter);
  extern int drm_add_edid_modes(struct drm_connector *connector, struct edid *edid);
@@@ -936,9 -920,6 +937,9 @@@ extern void drm_framebuffer_set_object(
  extern int drm_framebuffer_init(struct drm_device *dev,
                                struct drm_framebuffer *fb,
                                const struct drm_framebuffer_funcs *funcs);
 +extern void drm_framebuffer_unreference(struct drm_framebuffer *fb);
 +extern void drm_framebuffer_reference(struct drm_framebuffer *fb);
 +extern void drm_framebuffer_remove(struct drm_framebuffer *fb);
  extern void drm_framebuffer_cleanup(struct drm_framebuffer *fb);
  extern int drmfb_probe(struct drm_device *dev, struct drm_crtc *crtc);
  extern int drmfb_remove(struct drm_device *dev, struct drm_framebuffer *fb);