Merge branch 'drm-intel-next' of git://anongit.freedesktop.org/drm-intel into drm...
[cascardo/linux.git] / drivers / gpu / drm / i915 / i915_dma.c
index 1c6d227..fd06bff 100644 (file)
 #include <linux/pm_runtime.h>
 #include <linux/oom.h>
 
+static unsigned int i915_load_fail_count;
+
+bool __i915_inject_load_failure(const char *func, int line)
+{
+       if (i915_load_fail_count >= i915.inject_load_failure)
+               return false;
+
+       if (++i915_load_fail_count == i915.inject_load_failure) {
+               DRM_INFO("Injecting failure at checkpoint %u [%s:%d]\n",
+                        i915.inject_load_failure, func, line);
+               return true;
+       }
+
+       return false;
+}
+
+#define FDO_BUG_URL "https://bugs.freedesktop.org/enter_bug.cgi?product=DRI"
+#define FDO_BUG_MSG "Please file a bug at " FDO_BUG_URL " against DRM/Intel " \
+                   "providing the dmesg log by booting with drm.debug=0xf"
+
+void
+__i915_printk(struct drm_i915_private *dev_priv, const char *level,
+             const char *fmt, ...)
+{
+       static bool shown_bug_once;
+       struct device *dev = dev_priv->dev->dev;
+       bool is_error = level[1] <= KERN_ERR[1];
+       bool is_debug = level[1] == KERN_DEBUG[1];
+       struct va_format vaf;
+       va_list args;
+
+       if (is_debug && !(drm_debug & DRM_UT_DRIVER))
+               return;
+
+       va_start(args, fmt);
+
+       vaf.fmt = fmt;
+       vaf.va = &args;
+
+       dev_printk(level, dev, "[" DRM_NAME ":%ps] %pV",
+                  __builtin_return_address(0), &vaf);
+
+       if (is_error && !shown_bug_once) {
+               dev_notice(dev, "%s", FDO_BUG_MSG);
+               shown_bug_once = true;
+       }
+
+       va_end(args);
+}
+
+static bool i915_error_injected(struct drm_i915_private *dev_priv)
+{
+       return i915.inject_load_failure &&
+              i915_load_fail_count == i915.inject_load_failure;
+}
+
+#define i915_load_error(dev_priv, fmt, ...)                                 \
+       __i915_printk(dev_priv,                                              \
+                     i915_error_injected(dev_priv) ? KERN_DEBUG : KERN_ERR, \
+                     fmt, ##__VA_ARGS__)
 
 static int i915_getparam(struct drm_device *dev, void *data,
                         struct drm_file *file_priv)
@@ -87,16 +147,16 @@ static int i915_getparam(struct drm_device *dev, void *data,
                value = 1;
                break;
        case I915_PARAM_HAS_BSD:
-               value = intel_ring_initialized(&dev_priv->ring[VCS]);
+               value = intel_engine_initialized(&dev_priv->engine[VCS]);
                break;
        case I915_PARAM_HAS_BLT:
-               value = intel_ring_initialized(&dev_priv->ring[BCS]);
+               value = intel_engine_initialized(&dev_priv->engine[BCS]);
                break;
        case I915_PARAM_HAS_VEBOX:
-               value = intel_ring_initialized(&dev_priv->ring[VECS]);
+               value = intel_engine_initialized(&dev_priv->engine[VECS]);
                break;
        case I915_PARAM_HAS_BSD2:
-               value = intel_ring_initialized(&dev_priv->ring[VCS2]);
+               value = intel_engine_initialized(&dev_priv->engine[VCS2]);
                break;
        case I915_PARAM_HAS_RELAXED_FENCING:
                value = 1;
@@ -126,7 +186,7 @@ static int i915_getparam(struct drm_device *dev, void *data,
                value = 1;
                break;
        case I915_PARAM_HAS_SEMAPHORES:
-               value = i915_semaphore_is_enabled(dev);
+               value = i915_semaphore_is_enabled(dev_priv);
                break;
        case I915_PARAM_HAS_PRIME_VMAP_FLUSH:
                value = 1;
@@ -144,7 +204,7 @@ static int i915_getparam(struct drm_device *dev, void *data,
                value = 1;
                break;
        case I915_PARAM_CMD_PARSER_VERSION:
-               value = i915_cmd_parser_get_version();
+               value = i915_cmd_parser_get_version(dev_priv);
                break;
        case I915_PARAM_HAS_COHERENT_PHYS_GTT:
                value = 1;
@@ -163,8 +223,7 @@ static int i915_getparam(struct drm_device *dev, void *data,
                        return -ENODEV;
                break;
        case I915_PARAM_HAS_GPU_RESET:
-               value = i915.enable_hangcheck &&
-                       intel_has_gpu_reset(dev);
+               value = i915.enable_hangcheck && intel_has_gpu_reset(dev_priv);
                break;
        case I915_PARAM_HAS_RESOURCE_STREAMER:
                value = HAS_RESOURCE_STREAMER(dev);
@@ -197,13 +256,6 @@ static int i915_get_bridge_dev(struct drm_device *dev)
        return 0;
 }
 
-#define MCHBAR_I915 0x44
-#define MCHBAR_I965 0x48
-#define MCHBAR_SIZE (4*4096)
-
-#define DEVEN_REG 0x54
-#define   DEVEN_MCHBAR_EN (1 << 28)
-
 /* Allocate space for the MCH regs if needed, return nonzero on error */
 static int
 intel_alloc_mchbar_resource(struct drm_device *dev)
@@ -265,7 +317,7 @@ intel_setup_mchbar(struct drm_device *dev)
        dev_priv->mchbar_need_disable = false;
 
        if (IS_I915G(dev) || IS_I915GM(dev)) {
-               pci_read_config_dword(dev_priv->bridge_dev, DEVEN_REG, &temp);
+               pci_read_config_dword(dev_priv->bridge_dev, DEVEN, &temp);
                enabled = !!(temp & DEVEN_MCHBAR_EN);
        } else {
                pci_read_config_dword(dev_priv->bridge_dev, mchbar_reg, &temp);
@@ -283,7 +335,7 @@ intel_setup_mchbar(struct drm_device *dev)
 
        /* Space is allocated or reserved, so enable it. */
        if (IS_I915G(dev) || IS_I915GM(dev)) {
-               pci_write_config_dword(dev_priv->bridge_dev, DEVEN_REG,
+               pci_write_config_dword(dev_priv->bridge_dev, DEVEN,
                                       temp | DEVEN_MCHBAR_EN);
        } else {
                pci_read_config_dword(dev_priv->bridge_dev, mchbar_reg, &temp);
@@ -296,17 +348,24 @@ intel_teardown_mchbar(struct drm_device *dev)
 {
        struct drm_i915_private *dev_priv = dev->dev_private;
        int mchbar_reg = INTEL_INFO(dev)->gen >= 4 ? MCHBAR_I965 : MCHBAR_I915;
-       u32 temp;
 
        if (dev_priv->mchbar_need_disable) {
                if (IS_I915G(dev) || IS_I915GM(dev)) {
-                       pci_read_config_dword(dev_priv->bridge_dev, DEVEN_REG, &temp);
-                       temp &= ~DEVEN_MCHBAR_EN;
-                       pci_write_config_dword(dev_priv->bridge_dev, DEVEN_REG, temp);
+                       u32 deven_val;
+
+                       pci_read_config_dword(dev_priv->bridge_dev, DEVEN,
+                                             &deven_val);
+                       deven_val &= ~DEVEN_MCHBAR_EN;
+                       pci_write_config_dword(dev_priv->bridge_dev, DEVEN,
+                                              deven_val);
                } else {
-                       pci_read_config_dword(dev_priv->bridge_dev, mchbar_reg, &temp);
-                       temp &= ~1;
-                       pci_write_config_dword(dev_priv->bridge_dev, mchbar_reg, temp);
+                       u32 mchbar_val;
+
+                       pci_read_config_dword(dev_priv->bridge_dev, mchbar_reg,
+                                             &mchbar_val);
+                       mchbar_val &= ~1;
+                       pci_write_config_dword(dev_priv->bridge_dev, mchbar_reg,
+                                              mchbar_val);
                }
        }
 
@@ -365,11 +424,51 @@ static const struct vga_switcheroo_client_ops i915_switcheroo_ops = {
        .can_switch = i915_switcheroo_can_switch,
 };
 
+static void i915_gem_fini(struct drm_device *dev)
+{
+       struct drm_i915_private *dev_priv = to_i915(dev);
+
+       /*
+        * Neither the BIOS, ourselves or any other kernel
+        * expects the system to be in execlists mode on startup,
+        * so we need to reset the GPU back to legacy mode. And the only
+        * known way to disable logical contexts is through a GPU reset.
+        *
+        * So in order to leave the system in a known default configuration,
+        * always reset the GPU upon unload. Afterwards we then clean up the
+        * GEM state tracking, flushing off the requests and leaving the
+        * system in a known idle state.
+        *
+        * Note that is of the upmost importance that the GPU is idle and
+        * all stray writes are flushed *before* we dismantle the backing
+        * storage for the pinned objects.
+        *
+        * However, since we are uncertain that reseting the GPU on older
+        * machines is a good idea, we don't - just in case it leaves the
+        * machine in an unusable condition.
+        */
+       if (HAS_HW_CONTEXTS(dev)) {
+               int reset = intel_gpu_reset(dev_priv, ALL_ENGINES);
+               WARN_ON(reset && reset != -ENODEV);
+       }
+
+       mutex_lock(&dev->struct_mutex);
+       i915_gem_reset(dev);
+       i915_gem_cleanup_engines(dev);
+       i915_gem_context_fini(dev);
+       mutex_unlock(&dev->struct_mutex);
+
+       WARN_ON(!list_empty(&to_i915(dev)->context_list));
+}
+
 static int i915_load_modeset_init(struct drm_device *dev)
 {
        struct drm_i915_private *dev_priv = dev->dev_private;
        int ret;
 
+       if (i915_inject_load_failure())
+               return -ENODEV;
+
        ret = intel_bios_init(dev_priv);
        if (ret)
                DRM_INFO("failed to find VBIOS tables\n");
@@ -391,6 +490,9 @@ static int i915_load_modeset_init(struct drm_device *dev)
        if (ret)
                goto cleanup_vga_client;
 
+       /* must happen before intel_power_domains_init_hw() on VLV/CHV */
+       intel_update_rawclk(dev_priv);
+
        intel_power_domains_init_hw(dev_priv, false);
 
        intel_csr_ucode_init(dev_priv);
@@ -413,9 +515,6 @@ static int i915_load_modeset_init(struct drm_device *dev)
 
        intel_modeset_gem_init(dev);
 
-       /* Always safe in the mode setting case. */
-       /* FIXME: do pre/post-mode set stuff in core KMS code */
-       dev->vblank_disable_allowed = true;
        if (INTEL_INFO(dev)->num_pipes == 0)
                return 0;
 
@@ -443,16 +542,14 @@ static int i915_load_modeset_init(struct drm_device *dev)
        return 0;
 
 cleanup_gem:
-       mutex_lock(&dev->struct_mutex);
-       i915_gem_cleanup_ringbuffer(dev);
-       i915_gem_context_fini(dev);
-       mutex_unlock(&dev->struct_mutex);
+       i915_gem_fini(dev);
 cleanup_irq:
        intel_guc_ucode_fini(dev);
        drm_irq_uninstall(dev);
        intel_teardown_gmbus(dev);
 cleanup_csr:
        intel_csr_ucode_fini(dev_priv);
+       intel_power_domains_fini(dev_priv);
        vga_switcheroo_unregister_client(dev->pdev);
 cleanup_vga_client:
        vga_client_register(dev->pdev, NULL, NULL, NULL);
@@ -465,6 +562,7 @@ static int i915_kick_out_firmware_fb(struct drm_i915_private *dev_priv)
 {
        struct apertures_struct *ap;
        struct pci_dev *pdev = dev_priv->dev->pdev;
+       struct i915_ggtt *ggtt = &dev_priv->ggtt;
        bool primary;
        int ret;
 
@@ -472,8 +570,8 @@ static int i915_kick_out_firmware_fb(struct drm_i915_private *dev_priv)
        if (!ap)
                return -ENOMEM;
 
-       ap->ranges[0].base = dev_priv->gtt.mappable_base;
-       ap->ranges[0].size = dev_priv->gtt.mappable_end;
+       ap->ranges[0].base = ggtt->mappable_base;
+       ap->ranges[0].size = ggtt->mappable_end;
 
        primary =
                pdev->resource[PCI_ROM_RESOURCE].flags & IORESOURCE_ROM_SHADOW;
@@ -788,7 +886,7 @@ static void intel_device_info_runtime_init(struct drm_device *dev)
                DRM_INFO("Display disabled (module parameter)\n");
                info->num_pipes = 0;
        } else if (info->num_pipes > 0 &&
-                  (INTEL_INFO(dev)->gen == 7 || INTEL_INFO(dev)->gen == 8) &&
+                  (IS_GEN7(dev_priv) || IS_GEN8(dev_priv)) &&
                   HAS_PCH_SPLIT(dev)) {
                u32 fuse_strap = I915_READ(FUSE_STRAP);
                u32 sfuse_strap = I915_READ(SFUSE_STRAP);
@@ -812,7 +910,7 @@ static void intel_device_info_runtime_init(struct drm_device *dev)
                        DRM_INFO("PipeC fused off\n");
                        info->num_pipes -= 1;
                }
-       } else if (info->num_pipes > 0 && INTEL_INFO(dev)->gen == 9) {
+       } else if (info->num_pipes > 0 && IS_GEN9(dev_priv)) {
                u32 dfsm = I915_READ(SKL_DFSM);
                u8 disabled_mask = 0;
                bool invalid;
@@ -853,6 +951,12 @@ static void intel_device_info_runtime_init(struct drm_device *dev)
        else if (INTEL_INFO(dev)->gen >= 9)
                gen9_sseu_info_init(dev);
 
+       info->has_snoop = !info->has_llc;
+
+       /* Snooping is broken on BXT A stepping. */
+       if (IS_BXT_REVID(dev, 0, BXT_REVID_A1))
+               info->has_snoop = false;
+
        DRM_DEBUG_DRIVER("slice total: %u\n", info->slice_total);
        DRM_DEBUG_DRIVER("subslice total: %u\n", info->subslice_total);
        DRM_DEBUG_DRIVER("subslice per slice: %u\n", info->subslice_per_slice);
@@ -864,6 +968,20 @@ static void intel_device_info_runtime_init(struct drm_device *dev)
                         info->has_subslice_pg ? "y" : "n");
        DRM_DEBUG_DRIVER("has EU power gating: %s\n",
                         info->has_eu_pg ? "y" : "n");
+
+       i915.enable_execlists =
+               intel_sanitize_enable_execlists(dev_priv,
+                                               i915.enable_execlists);
+
+       /*
+        * i915.enable_ppgtt is read-only, so do an early pass to validate the
+        * user's requested state against the hardware/driver capabilities.  We
+        * do this now so that we can print out any log messages once rather
+        * than every time we check intel_enable_ppgtt().
+        */
+       i915.enable_ppgtt =
+               intel_sanitize_enable_ppgtt(dev_priv, i915.enable_ppgtt);
+       DRM_DEBUG_DRIVER("ppgtt mode: %i\n", i915.enable_ppgtt);
 }
 
 static void intel_init_dpio(struct drm_i915_private *dev_priv)
@@ -929,6 +1047,87 @@ static void i915_workqueues_cleanup(struct drm_i915_private *dev_priv)
        destroy_workqueue(dev_priv->wq);
 }
 
+/**
+ * i915_driver_init_early - setup state not requiring device access
+ * @dev_priv: device private
+ *
+ * Initialize everything that is a "SW-only" state, that is state not
+ * requiring accessing the device or exposing the driver via kernel internal
+ * or userspace interfaces. Example steps belonging here: lock initialization,
+ * system memory allocation, setting up device specific attributes and
+ * function hooks not requiring accessing the device.
+ */
+static int i915_driver_init_early(struct drm_i915_private *dev_priv,
+                                 struct drm_device *dev,
+                                 struct intel_device_info *info)
+{
+       struct intel_device_info *device_info;
+       int ret = 0;
+
+       if (i915_inject_load_failure())
+               return -ENODEV;
+
+       /* Setup the write-once "constant" device info */
+       device_info = (struct intel_device_info *)&dev_priv->info;
+       memcpy(device_info, info, sizeof(dev_priv->info));
+       device_info->device_id = dev->pdev->device;
+
+       BUG_ON(device_info->gen > sizeof(device_info->gen_mask) * BITS_PER_BYTE);
+       device_info->gen_mask = BIT(device_info->gen - 1);
+
+       spin_lock_init(&dev_priv->irq_lock);
+       spin_lock_init(&dev_priv->gpu_error.lock);
+       mutex_init(&dev_priv->backlight_lock);
+       spin_lock_init(&dev_priv->uncore.lock);
+       spin_lock_init(&dev_priv->mm.object_stat_lock);
+       spin_lock_init(&dev_priv->mmio_flip_lock);
+       mutex_init(&dev_priv->sb_lock);
+       mutex_init(&dev_priv->modeset_restore_lock);
+       mutex_init(&dev_priv->av_mutex);
+       mutex_init(&dev_priv->wm.wm_mutex);
+       mutex_init(&dev_priv->pps_mutex);
+
+       ret = i915_workqueues_init(dev_priv);
+       if (ret < 0)
+               return ret;
+
+       /* This must be called before any calls to HAS_PCH_* */
+       intel_detect_pch(dev);
+
+       intel_pm_setup(dev);
+       intel_init_dpio(dev_priv);
+       intel_power_domains_init(dev_priv);
+       intel_irq_init(dev_priv);
+       intel_init_display_hooks(dev_priv);
+       intel_init_clock_gating_hooks(dev_priv);
+       intel_init_audio_hooks(dev_priv);
+       i915_gem_load_init(dev);
+
+       intel_display_crc_init(dev);
+
+       i915_dump_device_info(dev_priv);
+
+       /* Not all pre-production machines fall into this category, only the
+        * very first ones. Almost everything should work, except for maybe
+        * suspend/resume. And we don't implement workarounds that affect only
+        * pre-production machines. */
+       if (IS_HSW_EARLY_SDV(dev))
+               DRM_INFO("This is an early pre-production Haswell machine. "
+                        "It may not be fully functional.\n");
+
+       return 0;
+}
+
+/**
+ * i915_driver_cleanup_early - cleanup the setup done in i915_driver_init_early()
+ * @dev_priv: device private
+ */
+static void i915_driver_cleanup_early(struct drm_i915_private *dev_priv)
+{
+       i915_gem_load_cleanup(dev_priv->dev);
+       i915_workqueues_cleanup(dev_priv);
+}
+
 static int i915_mmio_setup(struct drm_device *dev)
 {
        struct drm_i915_private *dev_priv = to_i915(dev);
@@ -970,104 +1169,107 @@ static void i915_mmio_cleanup(struct drm_device *dev)
 }
 
 /**
- * i915_driver_load - setup chip and create an initial config
- * @dev: DRM device
- * @flags: startup flags
+ * i915_driver_init_mmio - setup device MMIO
+ * @dev_priv: device private
  *
- * The driver load routine has to do several things:
- *   - drive output discovery via intel_modeset_init()
- *   - initialize the memory manager
- *   - allocate initial config memory
- *   - setup the DRM framebuffer with the allocated memory
+ * Setup minimal device state necessary for MMIO accesses later in the
+ * initialization sequence. The setup here should avoid any other device-wide
+ * side effects or exposing the driver via kernel internal or user space
+ * interfaces.
  */
-int i915_driver_load(struct drm_device *dev, unsigned long flags)
+static int i915_driver_init_mmio(struct drm_i915_private *dev_priv)
 {
-       struct drm_i915_private *dev_priv;
-       struct intel_device_info *info, *device_info;
-       int ret = 0;
-       uint32_t aperture_size;
-
-       info = (struct intel_device_info *) flags;
-
-       dev_priv = kzalloc(sizeof(*dev_priv), GFP_KERNEL);
-       if (dev_priv == NULL)
-               return -ENOMEM;
-
-       dev->dev_private = dev_priv;
-       dev_priv->dev = dev;
+       struct drm_device *dev = dev_priv->dev;
+       int ret;
 
-       /* Setup the write-once "constant" device info */
-       device_info = (struct intel_device_info *)&dev_priv->info;
-       memcpy(device_info, info, sizeof(dev_priv->info));
-       device_info->device_id = dev->pdev->device;
+       if (i915_inject_load_failure())
+               return -ENODEV;
 
-       spin_lock_init(&dev_priv->irq_lock);
-       spin_lock_init(&dev_priv->gpu_error.lock);
-       mutex_init(&dev_priv->backlight_lock);
-       spin_lock_init(&dev_priv->uncore.lock);
-       spin_lock_init(&dev_priv->mm.object_stat_lock);
-       spin_lock_init(&dev_priv->mmio_flip_lock);
-       mutex_init(&dev_priv->sb_lock);
-       mutex_init(&dev_priv->modeset_restore_lock);
-       mutex_init(&dev_priv->av_mutex);
+       if (i915_get_bridge_dev(dev))
+               return -EIO;
 
-       ret = i915_workqueues_init(dev_priv);
+       ret = i915_mmio_setup(dev);
        if (ret < 0)
-               goto out_free_priv;
+               goto put_bridge;
 
-       intel_pm_setup(dev);
+       intel_uncore_init(dev_priv);
 
-       intel_runtime_pm_get(dev_priv);
+       return 0;
 
-       intel_display_crc_init(dev);
+put_bridge:
+       pci_dev_put(dev_priv->bridge_dev);
 
-       i915_dump_device_info(dev_priv);
+       return ret;
+}
 
-       /* Not all pre-production machines fall into this category, only the
-        * very first ones. Almost everything should work, except for maybe
-        * suspend/resume. And we don't implement workarounds that affect only
       * pre-production machines. */
-       if (IS_HSW_EARLY_SDV(dev))
-               DRM_INFO("This is an early pre-production Haswell machine. "
-                        "It may not be fully functional.\n");
+/**
+ * i915_driver_cleanup_mmio - cleanup the setup done in i915_driver_init_mmio()
+ * @dev_priv: device private
+ */
+static void i915_driver_cleanup_mmio(struct drm_i915_private *dev_priv)
+{
+       struct drm_device *dev = dev_priv->dev;
 
-       if (i915_get_bridge_dev(dev)) {
-               ret = -EIO;
-               goto out_runtime_pm_put;
-       }
+       intel_uncore_fini(dev_priv);
+       i915_mmio_cleanup(dev);
+       pci_dev_put(dev_priv->bridge_dev);
+}
 
-       ret = i915_mmio_setup(dev);
-       if (ret < 0)
-               goto put_bridge;
+/**
+ * i915_driver_init_hw - setup state requiring device access
+ * @dev_priv: device private
+ *
+ * Setup state that requires accessing the device, but doesn't require
+ * exposing the driver via kernel internal or userspace interfaces.
+ */
+static int i915_driver_init_hw(struct drm_i915_private *dev_priv)
+{
+       struct drm_device *dev = dev_priv->dev;
+       struct i915_ggtt *ggtt = &dev_priv->ggtt;
+       uint32_t aperture_size;
+       int ret;
 
-       /* This must be called before any calls to HAS_PCH_* */
-       intel_detect_pch(dev);
+       if (i915_inject_load_failure())
+               return -ENODEV;
 
-       intel_uncore_init(dev);
+       intel_device_info_runtime_init(dev);
 
-       ret = i915_gem_gtt_init(dev);
+       ret = i915_ggtt_init_hw(dev);
        if (ret)
-               goto out_uncore_fini;
+               return ret;
+
+       ret = i915_ggtt_enable_hw(dev);
+       if (ret) {
+               DRM_ERROR("failed to enable GGTT\n");
+               goto out_ggtt;
+       }
 
        /* WARNING: Apparently we must kick fbdev drivers before vgacon,
         * otherwise the vga fbdev driver falls over. */
        ret = i915_kick_out_firmware_fb(dev_priv);
        if (ret) {
                DRM_ERROR("failed to remove conflicting framebuffer drivers\n");
-               goto out_gtt;
+               goto out_ggtt;
        }
 
        ret = i915_kick_out_vgacon(dev_priv);
        if (ret) {
                DRM_ERROR("failed to remove conflicting VGA console\n");
-               goto out_gtt;
+               goto out_ggtt;
        }
 
        pci_set_master(dev->pdev);
 
        /* overlay on gen2 is broken and can't address above 1G */
-       if (IS_GEN2(dev))
-               dma_set_coherent_mask(&dev->pdev->dev, DMA_BIT_MASK(30));
+       if (IS_GEN2(dev)) {
+               ret = dma_set_coherent_mask(&dev->pdev->dev, DMA_BIT_MASK(30));
+               if (ret) {
+                       DRM_ERROR("failed to set DMA mask\n");
+
+                       goto out_ggtt;
+               }
+       }
+
 
        /* 965GM sometimes incorrectly writes to hardware status page (HWS)
         * using 32bit addressing, overwriting memory if HWS is located
@@ -1077,29 +1279,37 @@ int i915_driver_load(struct drm_device *dev, unsigned long flags)
         * behaviour if any general state is accessed within a page above 4GB,
         * which also needs to be handled carefully.
         */
-       if (IS_BROADWATER(dev) || IS_CRESTLINE(dev))
-               dma_set_coherent_mask(&dev->pdev->dev, DMA_BIT_MASK(32));
+       if (IS_BROADWATER(dev) || IS_CRESTLINE(dev)) {
+               ret = dma_set_coherent_mask(&dev->pdev->dev, DMA_BIT_MASK(32));
+
+               if (ret) {
+                       DRM_ERROR("failed to set DMA mask\n");
 
-       aperture_size = dev_priv->gtt.mappable_end;
+                       goto out_ggtt;
+               }
+       }
+
+       aperture_size = ggtt->mappable_end;
 
-       dev_priv->gtt.mappable =
-               io_mapping_create_wc(dev_priv->gtt.mappable_base,
+       ggtt->mappable =
+               io_mapping_create_wc(ggtt->mappable_base,
                                     aperture_size);
-       if (dev_priv->gtt.mappable == NULL) {
+       if (!ggtt->mappable) {
                ret = -EIO;
-               goto out_gtt;
+               goto out_ggtt;
        }
 
-       dev_priv->gtt.mtrr = arch_phys_wc_add(dev_priv->gtt.mappable_base,
+       ggtt->mtrr = arch_phys_wc_add(ggtt->mappable_base,
                                              aperture_size);
 
-       intel_irq_init(dev_priv);
-       intel_uncore_sanitize(dev);
+       pm_qos_add_request(&dev_priv->pm_qos, PM_QOS_CPU_DMA_LATENCY,
+                          PM_QOS_DEFAULT_VALUE);
+
+       intel_uncore_sanitize(dev_priv);
 
        intel_opregion_setup(dev);
 
-       i915_gem_load_init(dev);
-       i915_gem_shrinker_init(dev_priv);
+       i915_gem_load_init_fences(dev_priv);
 
        /* On the 945G/GM, the chipset reports the MSI capability on the
         * integrated graphics even though the support isn't actually there
@@ -1117,75 +1327,154 @@ int i915_driver_load(struct drm_device *dev, unsigned long flags)
                        DRM_DEBUG_DRIVER("can't enable MSI");
        }
 
-       intel_device_info_runtime_init(dev);
+       return 0;
 
-       intel_init_dpio(dev_priv);
+out_ggtt:
+       i915_ggtt_cleanup_hw(dev);
 
-       if (INTEL_INFO(dev)->num_pipes) {
-               ret = drm_vblank_init(dev, INTEL_INFO(dev)->num_pipes);
-               if (ret)
-                       goto out_gem_unload;
-       }
+       return ret;
+}
 
-       intel_power_domains_init(dev_priv);
+/**
+ * i915_driver_cleanup_hw - cleanup the setup done in i915_driver_init_hw()
+ * @dev_priv: device private
+ */
+static void i915_driver_cleanup_hw(struct drm_i915_private *dev_priv)
+{
+       struct drm_device *dev = dev_priv->dev;
+       struct i915_ggtt *ggtt = &dev_priv->ggtt;
 
-       ret = i915_load_modeset_init(dev);
-       if (ret < 0) {
-               DRM_ERROR("failed to init modeset\n");
-               goto out_power_well;
-       }
+       if (dev->pdev->msi_enabled)
+               pci_disable_msi(dev->pdev);
 
+       pm_qos_remove_request(&dev_priv->pm_qos);
+       arch_phys_wc_del(ggtt->mtrr);
+       io_mapping_free(ggtt->mappable);
+       i915_ggtt_cleanup_hw(dev);
+}
+
+/**
+ * i915_driver_register - register the driver with the rest of the system
+ * @dev_priv: device private
+ *
+ * Perform any steps necessary to make the driver available via kernel
+ * internal or userspace interfaces.
+ */
+static void i915_driver_register(struct drm_i915_private *dev_priv)
+{
+       struct drm_device *dev = dev_priv->dev;
+
+       i915_gem_shrinker_init(dev_priv);
        /*
         * Notify a valid surface after modesetting,
         * when running inside a VM.
         */
-       if (intel_vgpu_active(dev))
+       if (intel_vgpu_active(dev_priv))
                I915_WRITE(vgtif_reg(display_ready), VGT_DRV_DISPLAY_READY);
 
        i915_setup_sysfs(dev);
 
-       if (INTEL_INFO(dev)->num_pipes) {
+       if (INTEL_INFO(dev_priv)->num_pipes) {
                /* Must be done after probing outputs */
                intel_opregion_init(dev);
                acpi_video_register();
        }
 
-       if (IS_GEN5(dev))
+       if (IS_GEN5(dev_priv))
                intel_gpu_ips_init(dev_priv);
 
-       intel_runtime_pm_enable(dev_priv);
-
        i915_audio_component_init(dev_priv);
+}
+
+/**
+ * i915_driver_unregister - cleanup the registration done in i915_driver_regiser()
+ * @dev_priv: device private
+ */
+static void i915_driver_unregister(struct drm_i915_private *dev_priv)
+{
+       i915_audio_component_cleanup(dev_priv);
+       intel_gpu_ips_teardown();
+       acpi_video_unregister();
+       intel_opregion_fini(dev_priv->dev);
+       i915_teardown_sysfs(dev_priv->dev);
+       i915_gem_shrinker_cleanup(dev_priv);
+}
+
+/**
+ * i915_driver_load - setup chip and create an initial config
+ * @dev: DRM device
+ * @flags: startup flags
+ *
+ * The driver load routine has to do several things:
+ *   - drive output discovery via intel_modeset_init()
+ *   - initialize the memory manager
+ *   - allocate initial config memory
+ *   - setup the DRM framebuffer with the allocated memory
+ */
+int i915_driver_load(struct drm_device *dev, unsigned long flags)
+{
+       struct drm_i915_private *dev_priv;
+       int ret = 0;
+
+       dev_priv = kzalloc(sizeof(*dev_priv), GFP_KERNEL);
+       if (dev_priv == NULL)
+               return -ENOMEM;
+
+       dev->dev_private = dev_priv;
+       /* Must be set before calling __i915_printk */
+       dev_priv->dev = dev;
+
+       ret = i915_driver_init_early(dev_priv, dev,
+                                    (struct intel_device_info *)flags);
+
+       if (ret < 0)
+               goto out_free_priv;
+
+       intel_runtime_pm_get(dev_priv);
+
+       ret = i915_driver_init_mmio(dev_priv);
+       if (ret < 0)
+               goto out_runtime_pm_put;
+
+       ret = i915_driver_init_hw(dev_priv);
+       if (ret < 0)
+               goto out_cleanup_mmio;
+
+       /*
+        * TODO: move the vblank init and parts of modeset init steps into one
+        * of the i915_driver_init_/i915_driver_register functions according
+        * to the role/effect of the given init step.
+        */
+       if (INTEL_INFO(dev)->num_pipes) {
+               ret = drm_vblank_init(dev, INTEL_INFO(dev)->num_pipes);
+               if (ret)
+                       goto out_cleanup_hw;
+       }
+
+       ret = i915_load_modeset_init(dev);
+       if (ret < 0)
+               goto out_cleanup_vblank;
+
+       i915_driver_register(dev_priv);
+
+       intel_runtime_pm_enable(dev_priv);
 
        intel_runtime_pm_put(dev_priv);
 
        return 0;
 
-out_power_well:
-       intel_power_domains_fini(dev_priv);
+out_cleanup_vblank:
        drm_vblank_cleanup(dev);
-out_gem_unload:
-       i915_gem_shrinker_cleanup(dev_priv);
-
-       if (dev->pdev->msi_enabled)
-               pci_disable_msi(dev->pdev);
-
-       intel_teardown_mchbar(dev);
-       pm_qos_remove_request(&dev_priv->pm_qos);
-       arch_phys_wc_del(dev_priv->gtt.mtrr);
-       io_mapping_free(dev_priv->gtt.mappable);
-out_gtt:
-       i915_global_gtt_cleanup(dev);
-out_uncore_fini:
-       intel_uncore_fini(dev);
-       i915_mmio_cleanup(dev);
-put_bridge:
-       pci_dev_put(dev_priv->bridge_dev);
-       i915_gem_load_cleanup(dev);
+out_cleanup_hw:
+       i915_driver_cleanup_hw(dev_priv);
+out_cleanup_mmio:
+       i915_driver_cleanup_mmio(dev_priv);
 out_runtime_pm_put:
        intel_runtime_pm_put(dev_priv);
-       i915_workqueues_cleanup(dev_priv);
+       i915_driver_cleanup_early(dev_priv);
 out_free_priv:
+       i915_load_error(dev_priv, "Device initialization failed (%d)\n", ret);
+
        kfree(dev_priv);
 
        return ret;
@@ -1198,26 +1487,15 @@ int i915_driver_unload(struct drm_device *dev)
 
        intel_fbdev_fini(dev);
 
-       i915_audio_component_cleanup(dev_priv);
-
        ret = i915_gem_suspend(dev);
        if (ret) {
                DRM_ERROR("failed to idle hardware: %d\n", ret);
                return ret;
        }
 
-       intel_power_domains_fini(dev_priv);
-
-       intel_gpu_ips_teardown();
-
-       i915_teardown_sysfs(dev);
-
-       i915_gem_shrinker_cleanup(dev_priv);
-
-       io_mapping_free(dev_priv->gtt.mappable);
-       arch_phys_wc_del(dev_priv->gtt.mtrr);
+       intel_display_power_get(dev_priv, POWER_DOMAIN_INIT);
 
-       acpi_video_unregister();
+       i915_driver_unregister(dev_priv);
 
        drm_vblank_cleanup(dev);
 
@@ -1246,31 +1524,21 @@ int i915_driver_unload(struct drm_device *dev)
        cancel_delayed_work_sync(&dev_priv->gpu_error.hangcheck_work);
        i915_destroy_error_state(dev);
 
-       if (dev->pdev->msi_enabled)
-               pci_disable_msi(dev->pdev);
-
-       intel_opregion_fini(dev);
-
        /* Flush any outstanding unpin_work. */
        flush_workqueue(dev_priv->wq);
 
        intel_guc_ucode_fini(dev);
-       mutex_lock(&dev->struct_mutex);
-       i915_gem_cleanup_ringbuffer(dev);
-       i915_gem_context_fini(dev);
-       mutex_unlock(&dev->struct_mutex);
+       i915_gem_fini(dev);
        intel_fbc_cleanup_cfb(dev_priv);
 
-       pm_qos_remove_request(&dev_priv->pm_qos);
+       intel_power_domains_fini(dev_priv);
 
-       i915_global_gtt_cleanup(dev);
+       i915_driver_cleanup_hw(dev_priv);
+       i915_driver_cleanup_mmio(dev_priv);
 
-       intel_uncore_fini(dev);
-       i915_mmio_cleanup(dev);
+       intel_display_power_put(dev_priv, POWER_DOMAIN_INIT);
 
-       i915_gem_load_cleanup(dev);
-       pci_dev_put(dev_priv->bridge_dev);
-       i915_workqueues_cleanup(dev_priv);
+       i915_driver_cleanup_early(dev_priv);
        kfree(dev_priv);
 
        return 0;
@@ -1368,15 +1636,15 @@ const struct drm_ioctl_desc i915_ioctls[] = {
        DRM_IOCTL_DEF_DRV(I915_GEM_GET_APERTURE, i915_gem_get_aperture_ioctl, DRM_RENDER_ALLOW),
        DRM_IOCTL_DEF_DRV(I915_GET_PIPE_FROM_CRTC_ID, intel_get_pipe_from_crtc_id, 0),
        DRM_IOCTL_DEF_DRV(I915_GEM_MADVISE, i915_gem_madvise_ioctl, DRM_RENDER_ALLOW),
-       DRM_IOCTL_DEF_DRV(I915_OVERLAY_PUT_IMAGE, intel_overlay_put_image, DRM_MASTER|DRM_CONTROL_ALLOW),
-       DRM_IOCTL_DEF_DRV(I915_OVERLAY_ATTRS, intel_overlay_attrs, DRM_MASTER|DRM_CONTROL_ALLOW),
+       DRM_IOCTL_DEF_DRV(I915_OVERLAY_PUT_IMAGE, intel_overlay_put_image_ioctl, DRM_MASTER|DRM_CONTROL_ALLOW),
+       DRM_IOCTL_DEF_DRV(I915_OVERLAY_ATTRS, intel_overlay_attrs_ioctl, DRM_MASTER|DRM_CONTROL_ALLOW),
        DRM_IOCTL_DEF_DRV(I915_SET_SPRITE_COLORKEY, intel_sprite_set_colorkey, DRM_MASTER|DRM_CONTROL_ALLOW),
        DRM_IOCTL_DEF_DRV(I915_GET_SPRITE_COLORKEY, drm_noop, DRM_MASTER|DRM_CONTROL_ALLOW),
        DRM_IOCTL_DEF_DRV(I915_GEM_WAIT, i915_gem_wait_ioctl, DRM_AUTH|DRM_RENDER_ALLOW),
        DRM_IOCTL_DEF_DRV(I915_GEM_CONTEXT_CREATE, i915_gem_context_create_ioctl, DRM_RENDER_ALLOW),
        DRM_IOCTL_DEF_DRV(I915_GEM_CONTEXT_DESTROY, i915_gem_context_destroy_ioctl, DRM_RENDER_ALLOW),
        DRM_IOCTL_DEF_DRV(I915_REG_READ, i915_reg_read_ioctl, DRM_RENDER_ALLOW),
-       DRM_IOCTL_DEF_DRV(I915_GET_RESET_STATS, i915_get_reset_stats_ioctl, DRM_RENDER_ALLOW),
+       DRM_IOCTL_DEF_DRV(I915_GET_RESET_STATS, i915_gem_context_reset_stats_ioctl, DRM_RENDER_ALLOW),
        DRM_IOCTL_DEF_DRV(I915_GEM_USERPTR, i915_gem_userptr_ioctl, DRM_RENDER_ALLOW),
        DRM_IOCTL_DEF_DRV(I915_GEM_CONTEXT_GETPARAM, i915_gem_context_getparam_ioctl, DRM_RENDER_ALLOW),
        DRM_IOCTL_DEF_DRV(I915_GEM_CONTEXT_SETPARAM, i915_gem_context_setparam_ioctl, DRM_RENDER_ALLOW),