diff --git a/drivers/gpu/drm/i915/i915_dma.c b/drivers/gpu/drm/i915/i915_dma.c index a71bb127e261..d35de1b9a2dd 100644 --- a/drivers/gpu/drm/i915/i915_dma.c +++ b/drivers/gpu/drm/i915/i915_dma.c @@ -1792,8 +1792,6 @@ int i915_driver_unload(struct drm_device *dev) list_del(&dev_priv->gtt.base.global_link); WARN_ON(!list_empty(&dev_priv->vm_list)); drm_mm_takedown(&dev_priv->gtt.base.mm); - if (dev_priv->regs != NULL) - pci_iounmap(dev->pdev, dev_priv->regs); intel_teardown_gmbus(dev); intel_teardown_mchbar(dev); @@ -1803,6 +1801,10 @@ int i915_driver_unload(struct drm_device *dev) dev_priv->gtt.base.cleanup(&dev_priv->gtt.base); + intel_uncore_fini(dev); + if (dev_priv->regs != NULL) + pci_iounmap(dev->pdev, dev_priv->regs); + if (dev_priv->slab) kmem_cache_destroy(dev_priv->slab); diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index bbe889dfc0ff..662c0ff0b049 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -408,6 +408,8 @@ struct intel_uncore { unsigned fifo_count; unsigned forcewake_count; + + struct delayed_work force_wake_work; }; #define DEV_INFO_FOR_EACH_FLAG(func, sep) \ @@ -1801,6 +1803,7 @@ extern void intel_uncore_early_sanitize(struct drm_device *dev); extern void intel_uncore_init(struct drm_device *dev); extern void intel_uncore_clear_errors(struct drm_device *dev); extern void intel_uncore_check_errors(struct drm_device *dev); +extern void intel_uncore_fini(struct drm_device *dev); void i915_enable_pipestat(drm_i915_private_t *dev_priv, int pipe, u32 mask); diff --git a/drivers/gpu/drm/i915/intel_uncore.c b/drivers/gpu/drm/i915/intel_uncore.c index 8649f1c36b00..f2753d9fb098 100644 --- a/drivers/gpu/drm/i915/intel_uncore.c +++ b/drivers/gpu/drm/i915/intel_uncore.c @@ -204,6 +204,18 @@ static void vlv_force_wake_put(struct drm_i915_private *dev_priv) gen6_gt_check_fifodbg(dev_priv); } +static void gen6_force_wake_work(struct work_struct *work) +{ + struct drm_i915_private *dev_priv = + container_of(work, typeof(*dev_priv), uncore.force_wake_work.work); + unsigned long irqflags; + + spin_lock_irqsave(&dev_priv->uncore.lock, irqflags); + if (--dev_priv->uncore.forcewake_count == 0) + dev_priv->uncore.funcs.force_wake_put(dev_priv); + spin_unlock_irqrestore(&dev_priv->uncore.lock, irqflags); +} + void intel_uncore_early_sanitize(struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; @@ -216,6 +228,9 @@ void intel_uncore_init(struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; + INIT_DELAYED_WORK(&dev_priv->uncore.force_wake_work, + gen6_force_wake_work); + if (IS_VALLEYVIEW(dev)) { dev_priv->uncore.funcs.force_wake_get = vlv_force_wake_get; dev_priv->uncore.funcs.force_wake_put = vlv_force_wake_put; @@ -261,6 +276,16 @@ void intel_uncore_init(struct drm_device *dev) } } +void intel_uncore_fini(struct drm_device *dev) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + + flush_delayed_work(&dev_priv->uncore.force_wake_work); + + /* Paranoia: make sure we have disabled everything before we exit. */ + intel_uncore_sanitize(dev); +} + static void intel_uncore_forcewake_reset(struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; @@ -306,8 +331,12 @@ void gen6_gt_force_wake_put(struct drm_i915_private *dev_priv) unsigned long irqflags; spin_lock_irqsave(&dev_priv->uncore.lock, irqflags); - if (--dev_priv->uncore.forcewake_count == 0) - dev_priv->uncore.funcs.force_wake_put(dev_priv); + if (--dev_priv->uncore.forcewake_count == 0) { + dev_priv->uncore.forcewake_count++; + mod_delayed_work(dev_priv->wq, + &dev_priv->uncore.force_wake_work, + 1); + } spin_unlock_irqrestore(&dev_priv->uncore.lock, irqflags); }