diff options
Diffstat (limited to 'drivers/gpu/drm/i915/i915_drv.c')
-rw-r--r-- | drivers/gpu/drm/i915/i915_drv.c | 359 |
1 files changed, 149 insertions, 210 deletions
diff --git a/drivers/gpu/drm/i915/i915_drv.c b/drivers/gpu/drm/i915/i915_drv.c index 2318b4c7a8f8..f990ab4c3efb 100644 --- a/drivers/gpu/drm/i915/i915_drv.c +++ b/drivers/gpu/drm/i915/i915_drv.c @@ -356,6 +356,19 @@ static const struct intel_device_info intel_cherryview_info = { CURSOR_OFFSETS, }; +static const struct intel_device_info intel_skylake_info = { + .is_preliminary = 1, + .is_skylake = 1, + .gen = 9, .num_pipes = 3, + .need_gfx_hws = 1, .has_hotplug = 1, + .ring_mask = RENDER_RING | BSD_RING | BLT_RING | VEBOX_RING, + .has_llc = 1, + .has_ddi = 1, + .has_fbc = 1, + GEN_DEFAULT_PIPEOFFSETS, + IVB_CURSOR_OFFSETS, +}; + /* * Make sure any device matches here are from most specific to most * general. For example, since the Quanta match is based on the subsystem @@ -392,7 +405,8 @@ static const struct intel_device_info intel_cherryview_info = { INTEL_BDW_GT12D_IDS(&intel_broadwell_d_info), \ INTEL_BDW_GT3M_IDS(&intel_broadwell_gt3m_info), \ INTEL_BDW_GT3D_IDS(&intel_broadwell_gt3d_info), \ - INTEL_CHV_IDS(&intel_cherryview_info) + INTEL_CHV_IDS(&intel_cherryview_info), \ + INTEL_SKL_IDS(&intel_skylake_info) static const struct pci_device_id pciidlist[] = { /* aka */ INTEL_PCI_IDS, @@ -449,7 +463,7 @@ void intel_detect_pch(struct drm_device *dev) dev_priv->pch_type = PCH_LPT; DRM_DEBUG_KMS("Found LynxPoint PCH\n"); WARN_ON(!IS_HASWELL(dev)); - WARN_ON(IS_ULT(dev)); + WARN_ON(IS_HSW_ULT(dev)); } else if (IS_BROADWELL(dev)) { dev_priv->pch_type = PCH_LPT; dev_priv->pch_id = @@ -460,7 +474,15 @@ void intel_detect_pch(struct drm_device *dev) dev_priv->pch_type = PCH_LPT; DRM_DEBUG_KMS("Found LynxPoint LP PCH\n"); WARN_ON(!IS_HASWELL(dev)); - WARN_ON(!IS_ULT(dev)); + WARN_ON(!IS_HSW_ULT(dev)); + } else if (id == INTEL_PCH_SPT_DEVICE_ID_TYPE) { + dev_priv->pch_type = PCH_SPT; + DRM_DEBUG_KMS("Found SunrisePoint PCH\n"); + WARN_ON(!IS_SKYLAKE(dev)); + } else if (id == INTEL_PCH_SPT_LP_DEVICE_ID_TYPE) { + dev_priv->pch_type = PCH_SPT; + DRM_DEBUG_KMS("Found SunrisePoint LP PCH\n"); + WARN_ON(!IS_SKYLAKE(dev)); } else continue; @@ -529,10 +551,10 @@ static void intel_suspend_encoders(struct drm_i915_private *dev_priv) } static int intel_suspend_complete(struct drm_i915_private *dev_priv); -static int intel_resume_prepare(struct drm_i915_private *dev_priv, - bool rpm_resume); +static int vlv_resume_prepare(struct drm_i915_private *dev_priv, + bool rpm_resume); -static int i915_drm_freeze(struct drm_device *dev) +static int i915_drm_suspend(struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; struct drm_crtc *crtc; @@ -562,6 +584,8 @@ static int i915_drm_freeze(struct drm_device *dev) return error; } + intel_suspend_gt_powersave(dev); + /* * Disable CRTCs directly since we want to preserve sw state * for _thaw. Also, power gate the CRTC power wells. @@ -573,16 +597,12 @@ static int i915_drm_freeze(struct drm_device *dev) intel_dp_mst_suspend(dev); - flush_delayed_work(&dev_priv->rps.delayed_resume_work); - - intel_runtime_pm_disable_interrupts(dev); + intel_runtime_pm_disable_interrupts(dev_priv); intel_hpd_cancel_work(dev_priv); intel_suspend_encoders(dev_priv); - intel_suspend_gt_powersave(dev); - - intel_modeset_suspend_hw(dev); + intel_suspend_hw(dev); } i915_gem_suspend_gtt_mappings(dev); @@ -608,7 +628,26 @@ static int i915_drm_freeze(struct drm_device *dev) return 0; } -int i915_suspend(struct drm_device *dev, pm_message_t state) +static int i915_drm_suspend_late(struct drm_device *drm_dev) +{ + struct drm_i915_private *dev_priv = drm_dev->dev_private; + int ret; + + ret = intel_suspend_complete(dev_priv); + + if (ret) { + DRM_ERROR("Suspend complete failed: %d\n", ret); + + return ret; + } + + pci_disable_device(drm_dev->pdev); + pci_set_power_state(drm_dev->pdev, PCI_D3hot); + + return 0; +} + +int i915_suspend_legacy(struct drm_device *dev, pm_message_t state) { int error; @@ -618,48 +657,25 @@ int i915_suspend(struct drm_device *dev, pm_message_t state) return -ENODEV; } - if (state.event == PM_EVENT_PRETHAW) - return 0; - + if (WARN_ON_ONCE(state.event != PM_EVENT_SUSPEND && + state.event != PM_EVENT_FREEZE)) + return -EINVAL; if (dev->switch_power_state == DRM_SWITCH_POWER_OFF) return 0; - error = i915_drm_freeze(dev); + error = i915_drm_suspend(dev); if (error) return error; - if (state.event == PM_EVENT_SUSPEND) { - /* Shut down the device */ - pci_disable_device(dev->pdev); - pci_set_power_state(dev->pdev, PCI_D3hot); - } - - return 0; + return i915_drm_suspend_late(dev); } -static int i915_drm_thaw_early(struct drm_device *dev) +static int i915_drm_resume(struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; - int ret; - - ret = intel_resume_prepare(dev_priv, false); - if (ret) - DRM_ERROR("Resume prepare failed: %d,Continuing resume\n", ret); - intel_uncore_early_sanitize(dev, true); - intel_uncore_sanitize(dev); - intel_power_domains_init_hw(dev_priv); - - return ret; -} - -static int __i915_drm_thaw(struct drm_device *dev, bool restore_gtt_mappings) -{ - struct drm_i915_private *dev_priv = dev->dev_private; - - if (drm_core_check_feature(dev, DRIVER_MODESET) && - restore_gtt_mappings) { + if (drm_core_check_feature(dev, DRIVER_MODESET)) { mutex_lock(&dev->struct_mutex); i915_gem_restore_gtt_mappings(dev); mutex_unlock(&dev->struct_mutex); @@ -680,30 +696,29 @@ static int __i915_drm_thaw(struct drm_device *dev, bool restore_gtt_mappings) } mutex_unlock(&dev->struct_mutex); - intel_runtime_pm_restore_interrupts(dev); + /* We need working interrupts for modeset enabling ... */ + intel_runtime_pm_enable_interrupts(dev_priv); intel_modeset_init_hw(dev); - { - unsigned long irqflags; - spin_lock_irqsave(&dev_priv->irq_lock, irqflags); - if (dev_priv->display.hpd_irq_setup) - dev_priv->display.hpd_irq_setup(dev); - spin_unlock_irqrestore(&dev_priv->irq_lock, irqflags); - } + spin_lock_irq(&dev_priv->irq_lock); + if (dev_priv->display.hpd_irq_setup) + dev_priv->display.hpd_irq_setup(dev); + spin_unlock_irq(&dev_priv->irq_lock); - intel_dp_mst_resume(dev); drm_modeset_lock_all(dev); intel_modeset_setup_hw_state(dev, true); drm_modeset_unlock_all(dev); + intel_dp_mst_resume(dev); + /* * ... but also need to make sure that hotplug processing * doesn't cause havoc. Like in the driver load code we don't * bother with the tiny race here where we might loose hotplug * notifications. * */ - intel_hpd_init(dev); + intel_hpd_init(dev_priv); /* Config may have changed between suspend and resume */ drm_helper_hpd_irq_event(dev); } @@ -718,21 +733,15 @@ static int __i915_drm_thaw(struct drm_device *dev, bool restore_gtt_mappings) intel_opregion_notify_adapter(dev, PCI_D0); - return 0; -} - -static int i915_drm_thaw(struct drm_device *dev) -{ - if (drm_core_check_feature(dev, DRIVER_MODESET)) - i915_check_and_clear_faults(dev); + drm_kms_helper_poll_enable(dev); - return __i915_drm_thaw(dev, true); + return 0; } -static int i915_resume_early(struct drm_device *dev) +static int i915_drm_resume_early(struct drm_device *dev) { - if (dev->switch_power_state == DRM_SWITCH_POWER_OFF) - return 0; + struct drm_i915_private *dev_priv = dev->dev_private; + int ret = 0; /* * We have a resume ordering issue with the snd-hda driver also @@ -748,33 +757,34 @@ static int i915_resume_early(struct drm_device *dev) pci_set_master(dev->pdev); - return i915_drm_thaw_early(dev); + if (IS_VALLEYVIEW(dev_priv)) + ret = vlv_resume_prepare(dev_priv, false); + if (ret) + DRM_ERROR("Resume prepare failed: %d,Continuing resume\n", ret); + + intel_uncore_early_sanitize(dev, true); + + if (IS_HASWELL(dev_priv) || IS_BROADWELL(dev_priv)) + hsw_disable_pc8(dev_priv); + + intel_uncore_sanitize(dev); + intel_power_domains_init_hw(dev_priv); + + return ret; } -int i915_resume(struct drm_device *dev) +int i915_resume_legacy(struct drm_device *dev) { - struct drm_i915_private *dev_priv = dev->dev_private; int ret; - /* - * Platforms with opregion should have sane BIOS, older ones (gen3 and - * earlier) need to restore the GTT mappings since the BIOS might clear - * all our scratch PTEs. - */ - ret = __i915_drm_thaw(dev, !dev_priv->opregion.header); + if (dev->switch_power_state == DRM_SWITCH_POWER_OFF) + return 0; + + ret = i915_drm_resume_early(dev); if (ret) return ret; - drm_kms_helper_poll_enable(dev); - return 0; -} - -static int i915_resume_legacy(struct drm_device *dev) -{ - i915_resume_early(dev); - i915_resume(dev); - - return 0; + return i915_drm_resume(dev); } /** @@ -820,6 +830,9 @@ int i915_reset(struct drm_device *dev) } } + if (i915_stop_ring_allow_warn(dev_priv)) + pr_notice("drm/i915: Resetting chip after gpu hang\n"); + if (ret) { DRM_ERROR("Failed to reset chip: %i\n", ret); mutex_unlock(&dev->struct_mutex); @@ -840,10 +853,7 @@ int i915_reset(struct drm_device *dev) * was running at the time of the reset (i.e. we weren't VT * switched away). */ - if (drm_core_check_feature(dev, DRIVER_MODESET) || - !dev_priv->ums.mm_suspended) { - dev_priv->ums.mm_suspended = 0; - + if (drm_core_check_feature(dev, DRIVER_MODESET)) { /* Used to prevent gem_check_wedged returning -EAGAIN during gpu reset */ dev_priv->gpu_error.reload_in_reset = true; @@ -923,15 +933,13 @@ static int i915_pm_suspend(struct device *dev) if (drm_dev->switch_power_state == DRM_SWITCH_POWER_OFF) return 0; - return i915_drm_freeze(drm_dev); + return i915_drm_suspend(drm_dev); } static int i915_pm_suspend_late(struct device *dev) { struct pci_dev *pdev = to_pci_dev(dev); struct drm_device *drm_dev = pci_get_drvdata(pdev); - struct drm_i915_private *dev_priv = drm_dev->dev_private; - int ret; /* * We have a suspedn ordering issue with the snd-hda driver also @@ -945,16 +953,7 @@ static int i915_pm_suspend_late(struct device *dev) if (drm_dev->switch_power_state == DRM_SWITCH_POWER_OFF) return 0; - ret = intel_suspend_complete(dev_priv); - - if (ret) - DRM_ERROR("Suspend complete failed: %d\n", ret); - else { - pci_disable_device(pdev); - pci_set_power_state(pdev, PCI_D3hot); - } - - return ret; + return i915_drm_suspend_late(drm_dev); } static int i915_pm_resume_early(struct device *dev) @@ -962,61 +961,21 @@ static int i915_pm_resume_early(struct device *dev) struct pci_dev *pdev = to_pci_dev(dev); struct drm_device *drm_dev = pci_get_drvdata(pdev); - return i915_resume_early(drm_dev); -} - -static int i915_pm_resume(struct device *dev) -{ - struct pci_dev *pdev = to_pci_dev(dev); - struct drm_device *drm_dev = pci_get_drvdata(pdev); - - return i915_resume(drm_dev); -} - -static int i915_pm_freeze(struct device *dev) -{ - struct pci_dev *pdev = to_pci_dev(dev); - struct drm_device *drm_dev = pci_get_drvdata(pdev); - - if (!drm_dev || !drm_dev->dev_private) { - dev_err(dev, "DRM not initialized, aborting suspend.\n"); - return -ENODEV; - } - - return i915_drm_freeze(drm_dev); -} - -static int i915_pm_freeze_late(struct device *dev) -{ - struct pci_dev *pdev = to_pci_dev(dev); - struct drm_device *drm_dev = pci_get_drvdata(pdev); - struct drm_i915_private *dev_priv = drm_dev->dev_private; - - return intel_suspend_complete(dev_priv); -} - -static int i915_pm_thaw_early(struct device *dev) -{ - struct pci_dev *pdev = to_pci_dev(dev); - struct drm_device *drm_dev = pci_get_drvdata(pdev); + if (drm_dev->switch_power_state == DRM_SWITCH_POWER_OFF) + return 0; - return i915_drm_thaw_early(drm_dev); + return i915_drm_resume_early(drm_dev); } -static int i915_pm_thaw(struct device *dev) +static int i915_pm_resume(struct device *dev) { struct pci_dev *pdev = to_pci_dev(dev); struct drm_device *drm_dev = pci_get_drvdata(pdev); - return i915_drm_thaw(drm_dev); -} - -static int i915_pm_poweroff(struct device *dev) -{ - struct pci_dev *pdev = to_pci_dev(dev); - struct drm_device *drm_dev = pci_get_drvdata(pdev); + if (drm_dev->switch_power_state == DRM_SWITCH_POWER_OFF) + return 0; - return i915_drm_freeze(drm_dev); + return i915_drm_resume(drm_dev); } static int hsw_suspend_complete(struct drm_i915_private *dev_priv) @@ -1026,25 +985,6 @@ static int hsw_suspend_complete(struct drm_i915_private *dev_priv) return 0; } -static int snb_resume_prepare(struct drm_i915_private *dev_priv, - bool rpm_resume) -{ - struct drm_device *dev = dev_priv->dev; - - if (rpm_resume) - intel_init_pch_refclk(dev); - - return 0; -} - -static int hsw_resume_prepare(struct drm_i915_private *dev_priv, - bool rpm_resume) -{ - hsw_disable_pc8(dev_priv); - - return 0; -} - /* * Save all Gunit registers that may be lost after a D3 and a subsequent * S0i[R123] transition. The list of registers needing a save/restore is @@ -1449,18 +1389,13 @@ static int intel_runtime_suspend(struct device *device) i915_gem_release_all_mmaps(dev_priv); mutex_unlock(&dev->struct_mutex); - /* - * rps.work can't be rearmed here, since we get here only after making - * sure the GPU is idle and the RPS freq is set to the minimum. See - * intel_mark_idle(). - */ - cancel_work_sync(&dev_priv->rps.work); - intel_runtime_pm_disable_interrupts(dev); + intel_suspend_gt_powersave(dev); + intel_runtime_pm_disable_interrupts(dev_priv); ret = intel_suspend_complete(dev_priv); if (ret) { DRM_ERROR("Runtime suspend failed, disabling it (%d)\n", ret); - intel_runtime_pm_restore_interrupts(dev); + intel_runtime_pm_enable_interrupts(dev_priv); return ret; } @@ -1502,7 +1437,7 @@ static int intel_runtime_resume(struct device *device) struct pci_dev *pdev = to_pci_dev(device); struct drm_device *dev = pci_get_drvdata(pdev); struct drm_i915_private *dev_priv = dev->dev_private; - int ret; + int ret = 0; if (WARN_ON_ONCE(!HAS_RUNTIME_PM(dev))) return -ENODEV; @@ -1512,7 +1447,13 @@ static int intel_runtime_resume(struct device *device) intel_opregion_notify_adapter(dev, PCI_D0); dev_priv->pm.suspended = false; - ret = intel_resume_prepare(dev_priv, true); + if (IS_GEN6(dev_priv)) + intel_init_pch_refclk(dev); + else if (IS_HASWELL(dev_priv) || IS_BROADWELL(dev_priv)) + hsw_disable_pc8(dev_priv); + else if (IS_VALLEYVIEW(dev_priv)) + ret = vlv_resume_prepare(dev_priv, true); + /* * No point of rolling back things in case of an error, as the best * we can do is to hope that things will still work (and disable RPM). @@ -1520,8 +1461,8 @@ static int intel_runtime_resume(struct device *device) i915_gem_init_swizzling(dev); gen6_update_ring_freq(dev); - intel_runtime_pm_restore_interrupts(dev); - intel_reset_gt_powersave(dev); + intel_runtime_pm_enable_interrupts(dev_priv); + intel_enable_gt_powersave(dev); if (ret) DRM_ERROR("Runtime resume failed, disabling it (%d)\n", ret); @@ -1550,41 +1491,41 @@ static int intel_suspend_complete(struct drm_i915_private *dev_priv) return ret; } -/* - * This function implements common functionality of runtime and system - * resume sequence. Variable rpm_resume used for implementing different - * code paths. - */ -static int intel_resume_prepare(struct drm_i915_private *dev_priv, - bool rpm_resume) -{ - struct drm_device *dev = dev_priv->dev; - int ret; - - if (IS_GEN6(dev)) - ret = snb_resume_prepare(dev_priv, rpm_resume); - else if (IS_HASWELL(dev) || IS_BROADWELL(dev)) - ret = hsw_resume_prepare(dev_priv, rpm_resume); - else if (IS_VALLEYVIEW(dev)) - ret = vlv_resume_prepare(dev_priv, rpm_resume); - else - ret = 0; - - return ret; -} - static const struct dev_pm_ops i915_pm_ops = { + /* + * S0ix (via system suspend) and S3 event handlers [PMSG_SUSPEND, + * PMSG_RESUME] + */ .suspend = i915_pm_suspend, .suspend_late = i915_pm_suspend_late, .resume_early = i915_pm_resume_early, .resume = i915_pm_resume, - .freeze = i915_pm_freeze, - .freeze_late = i915_pm_freeze_late, - .thaw_early = i915_pm_thaw_early, - .thaw = i915_pm_thaw, - .poweroff = i915_pm_poweroff, + + /* + * S4 event handlers + * @freeze, @freeze_late : called (1) before creating the + * hibernation image [PMSG_FREEZE] and + * (2) after rebooting, before restoring + * the image [PMSG_QUIESCE] + * @thaw, @thaw_early : called (1) after creating the hibernation + * image, before writing it [PMSG_THAW] + * and (2) after failing to create or + * restore the image [PMSG_RECOVER] + * @poweroff, @poweroff_late: called after writing the hibernation + * image, before rebooting [PMSG_HIBERNATE] + * @restore, @restore_early : called after rebooting and restoring the + * hibernation image [PMSG_RESTORE] + */ + .freeze = i915_pm_suspend, + .freeze_late = i915_pm_suspend_late, + .thaw_early = i915_pm_resume_early, + .thaw = i915_pm_resume, + .poweroff = i915_pm_suspend, + .poweroff_late = i915_pm_suspend_late, .restore_early = i915_pm_resume_early, .restore = i915_pm_resume, + + /* S0ix (via runtime suspend) event handlers */ .runtime_suspend = intel_runtime_suspend, .runtime_resume = intel_runtime_resume, }; @@ -1626,12 +1567,10 @@ static struct drm_driver driver = { .set_busid = drm_pci_set_busid, /* Used in place of i915_pm_ops for non-DRIVER_MODESET */ - .suspend = i915_suspend, + .suspend = i915_suspend_legacy, .resume = i915_resume_legacy, .device_is_agp = i915_driver_device_is_agp, - .master_create = i915_master_create, - .master_destroy = i915_master_destroy, #if defined(CONFIG_DEBUG_FS) .debugfs_init = i915_debugfs_init, .debugfs_cleanup = i915_debugfs_cleanup, @@ -1645,7 +1584,7 @@ static struct drm_driver driver = { .gem_prime_import = i915_gem_prime_import, .dumb_create = i915_gem_dumb_create, - .dumb_map_offset = i915_gem_mmap_gtt, + .dumb_map_offset = i915_gem_dumb_map_offset, .dumb_destroy = drm_gem_dumb_destroy, .ioctls = i915_ioctls, .fops = &i915_driver_fops, |