]> Pileus Git - ~andy/linux/blobdiff - drivers/gpu/drm/i915/i915_drv.c
drm/i915: fixup hangman rebase goof-up
[~andy/linux] / drivers / gpu / drm / i915 / i915_drv.c
index ae8a64f9f8453266326803432156c81219d246ab..e41aadef99378282a9bd49dbc9a1f4aee1277cb6 100644 (file)
@@ -84,6 +84,12 @@ MODULE_PARM_DESC(lvds_downclock,
                "Use panel (LVDS/eDP) downclocking for power savings "
                "(default: false)");
 
+int i915_lvds_channel_mode __read_mostly;
+module_param_named(lvds_channel_mode, i915_lvds_channel_mode, int, 0600);
+MODULE_PARM_DESC(lvds_channel_mode,
+                "Specify LVDS channel mode "
+                "(0=probe BIOS [default], 1=single-channel, 2=dual-channel)");
+
 int i915_panel_use_ssc __read_mostly = -1;
 module_param_named(lvds_use_ssc, i915_panel_use_ssc, int, 0600);
 MODULE_PARM_DESC(lvds_use_ssc,
@@ -93,8 +99,8 @@ MODULE_PARM_DESC(lvds_use_ssc,
 int i915_vbt_sdvo_panel_type __read_mostly = -1;
 module_param_named(vbt_sdvo_panel_type, i915_vbt_sdvo_panel_type, int, 0600);
 MODULE_PARM_DESC(vbt_sdvo_panel_type,
-               "Override selection of SDVO panel mode in the VBT "
-               "(default: auto)");
+               "Override/Ignore selection of SDVO panel mode in the VBT "
+               "(-2=ignore, -1=auto [default], index in VBT BIOS table)");
 
 static bool i915_try_reset __read_mostly = true;
 module_param_named(reset, i915_try_reset, bool, 0600);
@@ -209,6 +215,7 @@ static const struct intel_device_info intel_ironlake_d_info = {
        .gen = 5,
        .need_gfx_hws = 1, .has_hotplug = 1,
        .has_bsd_ring = 1,
+       .has_pch_split = 1,
 };
 
 static const struct intel_device_info intel_ironlake_m_info = {
@@ -216,6 +223,7 @@ static const struct intel_device_info intel_ironlake_m_info = {
        .need_gfx_hws = 1, .has_hotplug = 1,
        .has_fbc = 1,
        .has_bsd_ring = 1,
+       .has_pch_split = 1,
 };
 
 static const struct intel_device_info intel_sandybridge_d_info = {
@@ -224,6 +232,7 @@ static const struct intel_device_info intel_sandybridge_d_info = {
        .has_bsd_ring = 1,
        .has_blt_ring = 1,
        .has_llc = 1,
+       .has_pch_split = 1,
 };
 
 static const struct intel_device_info intel_sandybridge_m_info = {
@@ -233,6 +242,7 @@ static const struct intel_device_info intel_sandybridge_m_info = {
        .has_bsd_ring = 1,
        .has_blt_ring = 1,
        .has_llc = 1,
+       .has_pch_split = 1,
 };
 
 static const struct intel_device_info intel_ivybridge_d_info = {
@@ -241,6 +251,7 @@ static const struct intel_device_info intel_ivybridge_d_info = {
        .has_bsd_ring = 1,
        .has_blt_ring = 1,
        .has_llc = 1,
+       .has_pch_split = 1,
 };
 
 static const struct intel_device_info intel_ivybridge_m_info = {
@@ -250,6 +261,43 @@ static const struct intel_device_info intel_ivybridge_m_info = {
        .has_bsd_ring = 1,
        .has_blt_ring = 1,
        .has_llc = 1,
+       .has_pch_split = 1,
+};
+
+static const struct intel_device_info intel_valleyview_m_info = {
+       .gen = 7, .is_mobile = 1,
+       .need_gfx_hws = 1, .has_hotplug = 1,
+       .has_fbc = 0,
+       .has_bsd_ring = 1,
+       .has_blt_ring = 1,
+       .is_valleyview = 1,
+};
+
+static const struct intel_device_info intel_valleyview_d_info = {
+       .gen = 7,
+       .need_gfx_hws = 1, .has_hotplug = 1,
+       .has_fbc = 0,
+       .has_bsd_ring = 1,
+       .has_blt_ring = 1,
+       .is_valleyview = 1,
+};
+
+static const struct intel_device_info intel_haswell_d_info = {
+       .is_haswell = 1, .gen = 7,
+       .need_gfx_hws = 1, .has_hotplug = 1,
+       .has_bsd_ring = 1,
+       .has_blt_ring = 1,
+       .has_llc = 1,
+       .has_pch_split = 1,
+};
+
+static const struct intel_device_info intel_haswell_m_info = {
+       .is_haswell = 1, .gen = 7, .is_mobile = 1,
+       .need_gfx_hws = 1, .has_hotplug = 1,
+       .has_bsd_ring = 1,
+       .has_blt_ring = 1,
+       .has_llc = 1,
+       .has_pch_split = 1,
 };
 
 static const struct pci_device_id pciidlist[] = {              /* aka */
@@ -297,6 +345,13 @@ static const struct pci_device_id pciidlist[] = {          /* aka */
        INTEL_VGA_DEVICE(0x0162, &intel_ivybridge_d_info), /* GT2 desktop */
        INTEL_VGA_DEVICE(0x015a, &intel_ivybridge_d_info), /* GT1 server */
        INTEL_VGA_DEVICE(0x016a, &intel_ivybridge_d_info), /* GT2 server */
+       INTEL_VGA_DEVICE(0x0402, &intel_haswell_d_info), /* GT1 desktop */
+       INTEL_VGA_DEVICE(0x0412, &intel_haswell_d_info), /* GT2 desktop */
+       INTEL_VGA_DEVICE(0x040a, &intel_haswell_d_info), /* GT1 server */
+       INTEL_VGA_DEVICE(0x041a, &intel_haswell_d_info), /* GT2 server */
+       INTEL_VGA_DEVICE(0x0406, &intel_haswell_m_info), /* GT1 mobile */
+       INTEL_VGA_DEVICE(0x0416, &intel_haswell_m_info), /* GT2 mobile */
+       INTEL_VGA_DEVICE(0x0c16, &intel_haswell_d_info), /* SDV */
        {0, 0, 0}
 };
 
@@ -308,6 +363,7 @@ MODULE_DEVICE_TABLE(pci, pciidlist);
 #define INTEL_PCH_IBX_DEVICE_ID_TYPE   0x3b00
 #define INTEL_PCH_CPT_DEVICE_ID_TYPE   0x1c00
 #define INTEL_PCH_PPT_DEVICE_ID_TYPE   0x1e00
+#define INTEL_PCH_LPT_DEVICE_ID_TYPE   0x8c00
 
 void intel_detect_pch(struct drm_device *dev)
 {
@@ -328,20 +384,45 @@ void intel_detect_pch(struct drm_device *dev)
 
                        if (id == INTEL_PCH_IBX_DEVICE_ID_TYPE) {
                                dev_priv->pch_type = PCH_IBX;
+                               dev_priv->num_pch_pll = 2;
                                DRM_DEBUG_KMS("Found Ibex Peak PCH\n");
                        } else if (id == INTEL_PCH_CPT_DEVICE_ID_TYPE) {
                                dev_priv->pch_type = PCH_CPT;
+                               dev_priv->num_pch_pll = 2;
                                DRM_DEBUG_KMS("Found CougarPoint PCH\n");
                        } else if (id == INTEL_PCH_PPT_DEVICE_ID_TYPE) {
                                /* PantherPoint is CPT compatible */
                                dev_priv->pch_type = PCH_CPT;
+                               dev_priv->num_pch_pll = 2;
                                DRM_DEBUG_KMS("Found PatherPoint PCH\n");
+                       } else if (id == INTEL_PCH_LPT_DEVICE_ID_TYPE) {
+                               dev_priv->pch_type = PCH_LPT;
+                               dev_priv->num_pch_pll = 0;
+                               DRM_DEBUG_KMS("Found LynxPoint PCH\n");
                        }
+                       BUG_ON(dev_priv->num_pch_pll > I915_NUM_PLLS);
                }
                pci_dev_put(pch);
        }
 }
 
+bool i915_semaphore_is_enabled(struct drm_device *dev)
+{
+       if (INTEL_INFO(dev)->gen < 6)
+               return 0;
+
+       if (i915_semaphores >= 0)
+               return i915_semaphores;
+
+#ifdef CONFIG_INTEL_IOMMU
+       /* Enable semaphores on SNB when IO remapping is off */
+       if (INTEL_INFO(dev)->gen == 6 && intel_iommu_gfx_mapped)
+               return false;
+#endif
+
+       return 1;
+}
+
 void __gen6_gt_force_wake_get(struct drm_i915_private *dev_priv)
 {
        int count;
@@ -366,7 +447,7 @@ void __gen6_gt_force_wake_mt_get(struct drm_i915_private *dev_priv)
        while (count++ < 50 && (I915_READ_NOTRACE(FORCEWAKE_MT_ACK) & 1))
                udelay(10);
 
-       I915_WRITE_NOTRACE(FORCEWAKE_MT, (1<<16) | 1);
+       I915_WRITE_NOTRACE(FORCEWAKE_MT, _MASKED_BIT_ENABLE(1));
        POSTING_READ(FORCEWAKE_MT);
 
        count = 0;
@@ -408,7 +489,7 @@ void __gen6_gt_force_wake_put(struct drm_i915_private *dev_priv)
 
 void __gen6_gt_force_wake_mt_put(struct drm_i915_private *dev_priv)
 {
-       I915_WRITE_NOTRACE(FORCEWAKE_MT, (1<<16) | 0);
+       I915_WRITE_NOTRACE(FORCEWAKE_MT, _MASKED_BIT_DISABLE(1));
        /* The below doubles as a POSTING_READ */
        gen6_gt_check_fifodbg(dev_priv);
 }
@@ -446,6 +527,31 @@ int __gen6_gt_wait_for_fifo(struct drm_i915_private *dev_priv)
        return ret;
 }
 
+void vlv_force_wake_get(struct drm_i915_private *dev_priv)
+{
+       int count;
+
+       count = 0;
+
+       /* Already awake? */
+       if ((I915_READ(0x130094) & 0xa1) == 0xa1)
+               return;
+
+       I915_WRITE_NOTRACE(FORCEWAKE_VLV, 0xffffffff);
+       POSTING_READ(FORCEWAKE_VLV);
+
+       count = 0;
+       while (count++ < 50 && (I915_READ_NOTRACE(FORCEWAKE_ACK_VLV) & 1) == 0)
+               udelay(10);
+}
+
+void vlv_force_wake_put(struct drm_i915_private *dev_priv)
+{
+       I915_WRITE_NOTRACE(FORCEWAKE_VLV, 0xffff0000);
+       /* FIXME: confirm VLV behavior with Punit folks */
+       POSTING_READ(FORCEWAKE_VLV);
+}
+
 static int i915_drm_freeze(struct drm_device *dev)
 {
        struct drm_i915_private *dev_priv = dev->dev_private;
@@ -525,15 +631,16 @@ static int i915_drm_thaw(struct drm_device *dev)
 
        /* KMS EnterVT equivalent */
        if (drm_core_check_feature(dev, DRIVER_MODESET)) {
+               if (HAS_PCH_SPLIT(dev))
+                       ironlake_init_pch_refclk(dev);
+
                mutex_lock(&dev->struct_mutex);
                dev_priv->mm.suspended = 0;
 
                error = i915_gem_init_hw(dev);
                mutex_unlock(&dev->struct_mutex);
 
-               if (HAS_PCH_SPLIT(dev))
-                       ironlake_init_pch_refclk(dev);
-
+               intel_modeset_init_hw(dev);
                drm_mode_config_reset(dev);
                drm_irq_install(dev);
 
@@ -541,9 +648,6 @@ static int i915_drm_thaw(struct drm_device *dev)
                mutex_lock(&dev->mode_config.mutex);
                drm_helper_resume_force_mode(dev);
                mutex_unlock(&dev->mode_config.mutex);
-
-               if (IS_IRONLAKE_M(dev))
-                       ironlake_enable_rc6(dev);
        }
 
        intel_opregion_init(dev);
@@ -576,7 +680,7 @@ int i915_resume(struct drm_device *dev)
        return 0;
 }
 
-static int i8xx_do_reset(struct drm_device *dev, u8 flags)
+static int i8xx_do_reset(struct drm_device *dev)
 {
        struct drm_i915_private *dev_priv = dev->dev_private;
 
@@ -610,11 +714,12 @@ static int i965_reset_complete(struct drm_device *dev)
 {
        u8 gdrst;
        pci_read_config_byte(dev->pdev, I965_GDRST, &gdrst);
-       return gdrst & 0x1;
+       return (gdrst & GRDOM_RESET_ENABLE) == 0;
 }
 
-static int i965_do_reset(struct drm_device *dev, u8 flags)
+static int i965_do_reset(struct drm_device *dev)
 {
+       int ret;
        u8 gdrst;
 
        /*
@@ -623,20 +728,43 @@ static int i965_do_reset(struct drm_device *dev, u8 flags)
         * triggers the reset; when done, the hardware will clear it.
         */
        pci_read_config_byte(dev->pdev, I965_GDRST, &gdrst);
-       pci_write_config_byte(dev->pdev, I965_GDRST, gdrst | flags | 0x1);
+       pci_write_config_byte(dev->pdev, I965_GDRST,
+                             gdrst | GRDOM_RENDER |
+                             GRDOM_RESET_ENABLE);
+       ret =  wait_for(i965_reset_complete(dev), 500);
+       if (ret)
+               return ret;
+
+       /* We can't reset render&media without also resetting display ... */
+       pci_read_config_byte(dev->pdev, I965_GDRST, &gdrst);
+       pci_write_config_byte(dev->pdev, I965_GDRST,
+                             gdrst | GRDOM_MEDIA |
+                             GRDOM_RESET_ENABLE);
 
        return wait_for(i965_reset_complete(dev), 500);
 }
 
-static int ironlake_do_reset(struct drm_device *dev, u8 flags)
+static int ironlake_do_reset(struct drm_device *dev)
 {
        struct drm_i915_private *dev_priv = dev->dev_private;
-       u32 gdrst = I915_READ(MCHBAR_MIRROR_BASE + ILK_GDSR);
-       I915_WRITE(MCHBAR_MIRROR_BASE + ILK_GDSR, gdrst | flags | 0x1);
+       u32 gdrst;
+       int ret;
+
+       gdrst = I915_READ(MCHBAR_MIRROR_BASE + ILK_GDSR);
+       I915_WRITE(MCHBAR_MIRROR_BASE + ILK_GDSR,
+                  gdrst | GRDOM_RENDER | GRDOM_RESET_ENABLE);
+       ret = wait_for(I915_READ(MCHBAR_MIRROR_BASE + ILK_GDSR) & 0x1, 500);
+       if (ret)
+               return ret;
+
+       /* We can't reset render&media without also resetting display ... */
+       gdrst = I915_READ(MCHBAR_MIRROR_BASE + ILK_GDSR);
+       I915_WRITE(MCHBAR_MIRROR_BASE + ILK_GDSR,
+                  gdrst | GRDOM_MEDIA | GRDOM_RESET_ENABLE);
        return wait_for(I915_READ(MCHBAR_MIRROR_BASE + ILK_GDSR) & 0x1, 500);
 }
 
-static int gen6_do_reset(struct drm_device *dev, u8 flags)
+static int gen6_do_reset(struct drm_device *dev)
 {
        struct drm_i915_private *dev_priv = dev->dev_private;
        int     ret;
@@ -671,10 +799,44 @@ static int gen6_do_reset(struct drm_device *dev, u8 flags)
        return ret;
 }
 
+int intel_gpu_reset(struct drm_device *dev)
+{
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       int ret = -ENODEV;
+
+       switch (INTEL_INFO(dev)->gen) {
+       case 7:
+       case 6:
+               ret = gen6_do_reset(dev);
+               break;
+       case 5:
+               ret = ironlake_do_reset(dev);
+               break;
+       case 4:
+               ret = i965_do_reset(dev);
+               break;
+       case 2:
+               ret = i8xx_do_reset(dev);
+               break;
+       }
+
+       /* Also reset the gpu hangman. */
+       if (dev_priv->stop_rings) {
+               DRM_DEBUG("Simulated gpu hang, resetting stop_rings\n");
+               dev_priv->stop_rings = 0;
+               if (ret == -ENODEV) {
+                       DRM_ERROR("Reset not implemented, but ignoring "
+                                 "error for simulated gpu hangs\n");
+                       ret = 0;
+               }
+       }
+
+       return ret;
+}
+
 /**
  * i915_reset - reset chip after a hang
  * @dev: drm device to reset
- * @flags: reset domains
  *
  * Reset the chip.  Useful if a hang is detected. Returns zero on successful
  * reset or otherwise an error code.
@@ -687,14 +849,9 @@ static int gen6_do_reset(struct drm_device *dev, u8 flags)
  *   - re-init interrupt state
  *   - re-init display
  */
-int i915_reset(struct drm_device *dev, u8 flags)
+int i915_reset(struct drm_device *dev)
 {
        drm_i915_private_t *dev_priv = dev->dev_private;
-       /*
-        * We really should only reset the display subsystem if we actually
-        * need to
-        */
-       bool need_display = true;
        int ret;
 
        if (!i915_try_reset)
@@ -706,23 +863,11 @@ int i915_reset(struct drm_device *dev, u8 flags)
        i915_gem_reset(dev);
 
        ret = -ENODEV;
-       if (get_seconds() - dev_priv->last_gpu_reset < 5) {
+       if (get_seconds() - dev_priv->last_gpu_reset < 5)
                DRM_ERROR("GPU hanging too fast, declaring wedged!\n");
-       } else switch (INTEL_INFO(dev)->gen) {
-       case 7:
-       case 6:
-               ret = gen6_do_reset(dev, flags);
-               break;
-       case 5:
-               ret = ironlake_do_reset(dev, flags);
-               break;
-       case 4:
-               ret = i965_do_reset(dev, flags);
-               break;
-       case 2:
-               ret = i8xx_do_reset(dev, flags);
-               break;
-       }
+       else
+               ret = intel_gpu_reset(dev);
+
        dev_priv->last_gpu_reset = get_seconds();
        if (ret) {
                DRM_ERROR("Failed to reset chip.\n");
@@ -746,36 +891,28 @@ int i915_reset(struct drm_device *dev, u8 flags)
         */
        if (drm_core_check_feature(dev, DRIVER_MODESET) ||
                        !dev_priv->mm.suspended) {
+               struct intel_ring_buffer *ring;
+               int i;
+
                dev_priv->mm.suspended = 0;
 
                i915_gem_init_swizzling(dev);
 
-               dev_priv->ring[RCS].init(&dev_priv->ring[RCS]);
-               if (HAS_BSD(dev))
-                   dev_priv->ring[VCS].init(&dev_priv->ring[VCS]);
-               if (HAS_BLT(dev))
-                   dev_priv->ring[BCS].init(&dev_priv->ring[BCS]);
+               for_each_ring(ring, dev_priv, i)
+                       ring->init(ring);
 
+               i915_gem_context_init(dev);
                i915_gem_init_ppgtt(dev);
 
                mutex_unlock(&dev->struct_mutex);
-               drm_irq_uninstall(dev);
-               drm_mode_config_reset(dev);
-               drm_irq_install(dev);
-               mutex_lock(&dev->struct_mutex);
-       }
 
-       mutex_unlock(&dev->struct_mutex);
+               if (drm_core_check_feature(dev, DRIVER_MODESET))
+                       intel_modeset_init_hw(dev);
 
-       /*
-        * Perform a full modeset as on later generations, e.g. Ironlake, we may
-        * need to retrain the display link and cannot just restore the register
-        * values.
-        */
-       if (need_display) {
-               mutex_lock(&dev->mode_config.mutex);
-               drm_helper_resume_force_mode(dev);
-               mutex_unlock(&dev->mode_config.mutex);
+               drm_irq_uninstall(dev);
+               drm_irq_install(dev);
+       } else {
+               mutex_unlock(&dev->struct_mutex);
        }
 
        return 0;
@@ -874,7 +1011,7 @@ static const struct dev_pm_ops i915_pm_ops = {
        .restore = i915_pm_resume,
 };
 
-static struct vm_operations_struct i915_gem_vm_ops = {
+static const struct vm_operations_struct i915_gem_vm_ops = {
        .fault = i915_gem_fault,
        .open = drm_gem_vm_open,
        .close = drm_gem_vm_close,
@@ -901,7 +1038,7 @@ static struct drm_driver driver = {
         */
        .driver_features =
            DRIVER_USE_AGP | DRIVER_REQUIRE_AGP | /* DRIVER_USE_MTRR |*/
-           DRIVER_HAVE_IRQ | DRIVER_IRQ_SHARED | DRIVER_GEM,
+           DRIVER_HAVE_IRQ | DRIVER_IRQ_SHARED | DRIVER_GEM | DRIVER_PRIME,
        .load = i915_driver_load,
        .unload = i915_driver_unload,
        .open = i915_driver_open,
@@ -924,6 +1061,12 @@ static struct drm_driver driver = {
        .gem_init_object = i915_gem_init_object,
        .gem_free_object = i915_gem_free_object,
        .gem_vm_ops = &i915_gem_vm_ops,
+
+       .prime_handle_to_fd = drm_gem_prime_handle_to_fd,
+       .prime_fd_to_handle = drm_gem_prime_fd_to_handle,
+       .gem_prime_export = i915_gem_prime_export,
+       .gem_prime_import = i915_gem_prime_import,
+
        .dumb_create = i915_gem_dumb_create,
        .dumb_map_offset = i915_gem_mmap_gtt,
        .dumb_destroy = i915_gem_dumb_destroy,
@@ -993,6 +1136,13 @@ MODULE_AUTHOR(DRIVER_AUTHOR);
 MODULE_DESCRIPTION(DRIVER_DESC);
 MODULE_LICENSE("GPL and additional rights");
 
+/* We give fast paths for the really cool registers */
+#define NEEDS_FORCE_WAKE(dev_priv, reg) \
+       (((dev_priv)->info->gen >= 6) && \
+        ((reg) < 0x40000) &&            \
+        ((reg) != FORCEWAKE)) && \
+       (!IS_VALLEYVIEW((dev_priv)->dev))
+
 #define __i915_read(x, y) \
 u##x i915_read##x(struct drm_i915_private *dev_priv, u32 reg) { \
        u##x val = 0; \