}
 }
 
+static int i915_workqueues_init(struct drm_i915_private *dev_priv)
+{
+       /*
+        * The i915 workqueue is primarily used for batched retirement of
+        * requests (and thus managing bo) once the task has been completed
+        * by the GPU. i915_gem_retire_requests() is called directly when we
+        * need high-priority retirement, such as waiting for an explicit
+        * bo.
+        *
+        * It is also used for periodic low-priority events, such as
+        * idle-timers and recording error state.
+        *
+        * All tasks on the workqueue are expected to acquire the dev mutex
+        * so there is no point in running more than one instance of the
+        * workqueue at any time.  Use an ordered one.
+        */
+       dev_priv->wq = alloc_ordered_workqueue("i915", 0);
+       if (dev_priv->wq == NULL)
+               goto out_err;
+
+       dev_priv->hotplug.dp_wq = alloc_ordered_workqueue("i915-dp", 0);
+       if (dev_priv->hotplug.dp_wq == NULL)
+               goto out_free_wq;
+
+       dev_priv->gpu_error.hangcheck_wq =
+               alloc_ordered_workqueue("i915-hangcheck", 0);
+       if (dev_priv->gpu_error.hangcheck_wq == NULL)
+               goto out_free_dp_wq;
+
+       return 0;
+
+out_free_dp_wq:
+       destroy_workqueue(dev_priv->hotplug.dp_wq);
+out_free_wq:
+       destroy_workqueue(dev_priv->wq);
+out_err:
+       DRM_ERROR("Failed to allocate workqueues.\n");
+
+       return -ENOMEM;
+}
+
+static void i915_workqueues_cleanup(struct drm_i915_private *dev_priv)
+{
+       destroy_workqueue(dev_priv->gpu_error.hangcheck_wq);
+       destroy_workqueue(dev_priv->hotplug.dp_wq);
+       destroy_workqueue(dev_priv->wq);
+}
+
 /**
  * i915_driver_load - setup chip and create an initial config
  * @dev: DRM device
        mutex_init(&dev_priv->modeset_restore_lock);
        mutex_init(&dev_priv->av_mutex);
 
+       ret = i915_workqueues_init(dev_priv);
+       if (ret < 0)
+               goto out_free_priv;
+
        intel_pm_setup(dev);
 
        intel_runtime_pm_get(dev_priv);
        dev_priv->gtt.mtrr = arch_phys_wc_add(dev_priv->gtt.mappable_base,
                                              aperture_size);
 
-       /* The i915 workqueue is primarily used for batched retirement of
-        * requests (and thus managing bo) once the task has been completed
-        * by the GPU. i915_gem_retire_requests() is called directly when we
-        * need high-priority retirement, such as waiting for an explicit
-        * bo.
-        *
-        * It is also used for periodic low-priority events, such as
-        * idle-timers and recording error state.
-        *
-        * All tasks on the workqueue are expected to acquire the dev mutex
-        * so there is no point in running more than one instance of the
-        * workqueue at any time.  Use an ordered one.
-        */
-       dev_priv->wq = alloc_ordered_workqueue("i915", 0);
-       if (dev_priv->wq == NULL) {
-               DRM_ERROR("Failed to create our workqueue.\n");
-               ret = -ENOMEM;
-               goto out_mtrrfree;
-       }
-
-       dev_priv->hotplug.dp_wq = alloc_ordered_workqueue("i915-dp", 0);
-       if (dev_priv->hotplug.dp_wq == NULL) {
-               DRM_ERROR("Failed to create our dp workqueue.\n");
-               ret = -ENOMEM;
-               goto out_freewq;
-       }
-
-       dev_priv->gpu_error.hangcheck_wq =
-               alloc_ordered_workqueue("i915-hangcheck", 0);
-       if (dev_priv->gpu_error.hangcheck_wq == NULL) {
-               DRM_ERROR("Failed to create our hangcheck workqueue.\n");
-               ret = -ENOMEM;
-               goto out_freedpwq;
-       }
-
        intel_irq_init(dev_priv);
        intel_uncore_sanitize(dev);
 
 
        intel_teardown_mchbar(dev);
        pm_qos_remove_request(&dev_priv->pm_qos);
-       destroy_workqueue(dev_priv->gpu_error.hangcheck_wq);
-out_freedpwq:
-       destroy_workqueue(dev_priv->hotplug.dp_wq);
-out_freewq:
-       destroy_workqueue(dev_priv->wq);
-out_mtrrfree:
        arch_phys_wc_del(dev_priv->gtt.mtrr);
        io_mapping_free(dev_priv->gtt.mappable);
 out_gtt:
        i915_gem_load_cleanup(dev);
 out_runtime_pm_put:
        intel_runtime_pm_put(dev_priv);
-
+       i915_workqueues_cleanup(dev_priv);
+out_free_priv:
        kfree(dev_priv);
+
        return ret;
 }
 
 
        intel_teardown_mchbar(dev);
 
-       destroy_workqueue(dev_priv->hotplug.dp_wq);
-       destroy_workqueue(dev_priv->wq);
-       destroy_workqueue(dev_priv->gpu_error.hangcheck_wq);
        pm_qos_remove_request(&dev_priv->pm_qos);
 
        i915_global_gtt_cleanup(dev);
 
        i915_gem_load_cleanup(dev);
        pci_dev_put(dev_priv->bridge_dev);
+       i915_workqueues_cleanup(dev_priv);
        kfree(dev_priv);
 
        return 0;