162306a36Sopenharmony_ci/* i915_drv.c -- i830,i845,i855,i865,i915 driver -*- linux-c -*- 262306a36Sopenharmony_ci */ 362306a36Sopenharmony_ci/* 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Copyright 2003 Tungsten Graphics, Inc., Cedar Park, Texas. 662306a36Sopenharmony_ci * All Rights Reserved. 762306a36Sopenharmony_ci * 862306a36Sopenharmony_ci * Permission is hereby granted, free of charge, to any person obtaining a 962306a36Sopenharmony_ci * copy of this software and associated documentation files (the 1062306a36Sopenharmony_ci * "Software"), to deal in the Software without restriction, including 1162306a36Sopenharmony_ci * without limitation the rights to use, copy, modify, merge, publish, 1262306a36Sopenharmony_ci * distribute, sub license, and/or sell copies of the Software, and to 1362306a36Sopenharmony_ci * permit persons to whom the Software is furnished to do so, subject to 1462306a36Sopenharmony_ci * the following conditions: 1562306a36Sopenharmony_ci * 1662306a36Sopenharmony_ci * The above copyright notice and this permission notice (including the 1762306a36Sopenharmony_ci * next paragraph) shall be included in all copies or substantial portions 1862306a36Sopenharmony_ci * of the Software. 1962306a36Sopenharmony_ci * 2062306a36Sopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 2162306a36Sopenharmony_ci * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 2262306a36Sopenharmony_ci * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. 2362306a36Sopenharmony_ci * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR 2462306a36Sopenharmony_ci * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 2562306a36Sopenharmony_ci * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 2662306a36Sopenharmony_ci * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 2762306a36Sopenharmony_ci * 2862306a36Sopenharmony_ci */ 2962306a36Sopenharmony_ci 3062306a36Sopenharmony_ci#include <linux/acpi.h> 3162306a36Sopenharmony_ci#include <linux/device.h> 3262306a36Sopenharmony_ci#include <linux/module.h> 3362306a36Sopenharmony_ci#include <linux/oom.h> 3462306a36Sopenharmony_ci#include <linux/pci.h> 3562306a36Sopenharmony_ci#include <linux/pm.h> 3662306a36Sopenharmony_ci#include <linux/pm_runtime.h> 3762306a36Sopenharmony_ci#include <linux/slab.h> 3862306a36Sopenharmony_ci#include <linux/string_helpers.h> 3962306a36Sopenharmony_ci#include <linux/vga_switcheroo.h> 4062306a36Sopenharmony_ci#include <linux/vt.h> 4162306a36Sopenharmony_ci 4262306a36Sopenharmony_ci#include <drm/drm_aperture.h> 4362306a36Sopenharmony_ci#include <drm/drm_atomic_helper.h> 4462306a36Sopenharmony_ci#include <drm/drm_ioctl.h> 4562306a36Sopenharmony_ci#include <drm/drm_managed.h> 4662306a36Sopenharmony_ci#include <drm/drm_probe_helper.h> 4762306a36Sopenharmony_ci 4862306a36Sopenharmony_ci#include "display/intel_acpi.h" 4962306a36Sopenharmony_ci#include "display/intel_bw.h" 5062306a36Sopenharmony_ci#include "display/intel_cdclk.h" 5162306a36Sopenharmony_ci#include "display/intel_display_driver.h" 5262306a36Sopenharmony_ci#include "display/intel_display_types.h" 5362306a36Sopenharmony_ci#include "display/intel_dmc.h" 5462306a36Sopenharmony_ci#include "display/intel_dp.h" 5562306a36Sopenharmony_ci#include "display/intel_dpt.h" 5662306a36Sopenharmony_ci#include "display/intel_fbdev.h" 5762306a36Sopenharmony_ci#include "display/intel_hotplug.h" 5862306a36Sopenharmony_ci#include "display/intel_overlay.h" 5962306a36Sopenharmony_ci#include "display/intel_pch_refclk.h" 6062306a36Sopenharmony_ci#include "display/intel_pipe_crc.h" 6162306a36Sopenharmony_ci#include "display/intel_pps.h" 6262306a36Sopenharmony_ci#include "display/intel_sprite.h" 6362306a36Sopenharmony_ci#include "display/intel_vga.h" 6462306a36Sopenharmony_ci#include "display/skl_watermark.h" 6562306a36Sopenharmony_ci 6662306a36Sopenharmony_ci#include "gem/i915_gem_context.h" 6762306a36Sopenharmony_ci#include "gem/i915_gem_create.h" 6862306a36Sopenharmony_ci#include "gem/i915_gem_dmabuf.h" 6962306a36Sopenharmony_ci#include "gem/i915_gem_ioctls.h" 7062306a36Sopenharmony_ci#include "gem/i915_gem_mman.h" 7162306a36Sopenharmony_ci#include "gem/i915_gem_pm.h" 7262306a36Sopenharmony_ci#include "gt/intel_gt.h" 7362306a36Sopenharmony_ci#include "gt/intel_gt_pm.h" 7462306a36Sopenharmony_ci#include "gt/intel_rc6.h" 7562306a36Sopenharmony_ci 7662306a36Sopenharmony_ci#include "pxp/intel_pxp.h" 7762306a36Sopenharmony_ci#include "pxp/intel_pxp_debugfs.h" 7862306a36Sopenharmony_ci#include "pxp/intel_pxp_pm.h" 7962306a36Sopenharmony_ci 8062306a36Sopenharmony_ci#include "soc/intel_dram.h" 8162306a36Sopenharmony_ci#include "soc/intel_gmch.h" 8262306a36Sopenharmony_ci 8362306a36Sopenharmony_ci#include "i915_debugfs.h" 8462306a36Sopenharmony_ci#include "i915_driver.h" 8562306a36Sopenharmony_ci#include "i915_drm_client.h" 8662306a36Sopenharmony_ci#include "i915_drv.h" 8762306a36Sopenharmony_ci#include "i915_file_private.h" 8862306a36Sopenharmony_ci#include "i915_getparam.h" 8962306a36Sopenharmony_ci#include "i915_hwmon.h" 9062306a36Sopenharmony_ci#include "i915_ioc32.h" 9162306a36Sopenharmony_ci#include "i915_ioctl.h" 9262306a36Sopenharmony_ci#include "i915_irq.h" 9362306a36Sopenharmony_ci#include "i915_memcpy.h" 9462306a36Sopenharmony_ci#include "i915_perf.h" 9562306a36Sopenharmony_ci#include "i915_query.h" 9662306a36Sopenharmony_ci#include "i915_suspend.h" 9762306a36Sopenharmony_ci#include "i915_switcheroo.h" 9862306a36Sopenharmony_ci#include "i915_sysfs.h" 9962306a36Sopenharmony_ci#include "i915_utils.h" 10062306a36Sopenharmony_ci#include "i915_vgpu.h" 10162306a36Sopenharmony_ci#include "intel_clock_gating.h" 10262306a36Sopenharmony_ci#include "intel_gvt.h" 10362306a36Sopenharmony_ci#include "intel_memory_region.h" 10462306a36Sopenharmony_ci#include "intel_pci_config.h" 10562306a36Sopenharmony_ci#include "intel_pcode.h" 10662306a36Sopenharmony_ci#include "intel_region_ttm.h" 10762306a36Sopenharmony_ci#include "vlv_suspend.h" 10862306a36Sopenharmony_ci 10962306a36Sopenharmony_cistatic const struct drm_driver i915_drm_driver; 11062306a36Sopenharmony_ci 11162306a36Sopenharmony_cistatic int i915_workqueues_init(struct drm_i915_private *dev_priv) 11262306a36Sopenharmony_ci{ 11362306a36Sopenharmony_ci /* 11462306a36Sopenharmony_ci * The i915 workqueue is primarily used for batched retirement of 11562306a36Sopenharmony_ci * requests (and thus managing bo) once the task has been completed 11662306a36Sopenharmony_ci * by the GPU. i915_retire_requests() is called directly when we 11762306a36Sopenharmony_ci * need high-priority retirement, such as waiting for an explicit 11862306a36Sopenharmony_ci * bo. 11962306a36Sopenharmony_ci * 12062306a36Sopenharmony_ci * It is also used for periodic low-priority events, such as 12162306a36Sopenharmony_ci * idle-timers and recording error state. 12262306a36Sopenharmony_ci * 12362306a36Sopenharmony_ci * All tasks on the workqueue are expected to acquire the dev mutex 12462306a36Sopenharmony_ci * so there is no point in running more than one instance of the 12562306a36Sopenharmony_ci * workqueue at any time. Use an ordered one. 12662306a36Sopenharmony_ci */ 12762306a36Sopenharmony_ci dev_priv->wq = alloc_ordered_workqueue("i915", 0); 12862306a36Sopenharmony_ci if (dev_priv->wq == NULL) 12962306a36Sopenharmony_ci goto out_err; 13062306a36Sopenharmony_ci 13162306a36Sopenharmony_ci dev_priv->display.hotplug.dp_wq = alloc_ordered_workqueue("i915-dp", 0); 13262306a36Sopenharmony_ci if (dev_priv->display.hotplug.dp_wq == NULL) 13362306a36Sopenharmony_ci goto out_free_wq; 13462306a36Sopenharmony_ci 13562306a36Sopenharmony_ci /* 13662306a36Sopenharmony_ci * The unordered i915 workqueue should be used for all work 13762306a36Sopenharmony_ci * scheduling that do not require running in order, which used 13862306a36Sopenharmony_ci * to be scheduled on the system_wq before moving to a driver 13962306a36Sopenharmony_ci * instance due deprecation of flush_scheduled_work(). 14062306a36Sopenharmony_ci */ 14162306a36Sopenharmony_ci dev_priv->unordered_wq = alloc_workqueue("i915-unordered", 0, 0); 14262306a36Sopenharmony_ci if (dev_priv->unordered_wq == NULL) 14362306a36Sopenharmony_ci goto out_free_dp_wq; 14462306a36Sopenharmony_ci 14562306a36Sopenharmony_ci return 0; 14662306a36Sopenharmony_ci 14762306a36Sopenharmony_ciout_free_dp_wq: 14862306a36Sopenharmony_ci destroy_workqueue(dev_priv->display.hotplug.dp_wq); 14962306a36Sopenharmony_ciout_free_wq: 15062306a36Sopenharmony_ci destroy_workqueue(dev_priv->wq); 15162306a36Sopenharmony_ciout_err: 15262306a36Sopenharmony_ci drm_err(&dev_priv->drm, "Failed to allocate workqueues.\n"); 15362306a36Sopenharmony_ci 15462306a36Sopenharmony_ci return -ENOMEM; 15562306a36Sopenharmony_ci} 15662306a36Sopenharmony_ci 15762306a36Sopenharmony_cistatic void i915_workqueues_cleanup(struct drm_i915_private *dev_priv) 15862306a36Sopenharmony_ci{ 15962306a36Sopenharmony_ci destroy_workqueue(dev_priv->unordered_wq); 16062306a36Sopenharmony_ci destroy_workqueue(dev_priv->display.hotplug.dp_wq); 16162306a36Sopenharmony_ci destroy_workqueue(dev_priv->wq); 16262306a36Sopenharmony_ci} 16362306a36Sopenharmony_ci 16462306a36Sopenharmony_ci/* 16562306a36Sopenharmony_ci * We don't keep the workarounds for pre-production hardware, so we expect our 16662306a36Sopenharmony_ci * driver to fail on these machines in one way or another. A little warning on 16762306a36Sopenharmony_ci * dmesg may help both the user and the bug triagers. 16862306a36Sopenharmony_ci * 16962306a36Sopenharmony_ci * Our policy for removing pre-production workarounds is to keep the 17062306a36Sopenharmony_ci * current gen workarounds as a guide to the bring-up of the next gen 17162306a36Sopenharmony_ci * (workarounds have a habit of persisting!). Anything older than that 17262306a36Sopenharmony_ci * should be removed along with the complications they introduce. 17362306a36Sopenharmony_ci */ 17462306a36Sopenharmony_cistatic void intel_detect_preproduction_hw(struct drm_i915_private *dev_priv) 17562306a36Sopenharmony_ci{ 17662306a36Sopenharmony_ci bool pre = false; 17762306a36Sopenharmony_ci 17862306a36Sopenharmony_ci pre |= IS_HASWELL_EARLY_SDV(dev_priv); 17962306a36Sopenharmony_ci pre |= IS_SKYLAKE(dev_priv) && INTEL_REVID(dev_priv) < 0x6; 18062306a36Sopenharmony_ci pre |= IS_BROXTON(dev_priv) && INTEL_REVID(dev_priv) < 0xA; 18162306a36Sopenharmony_ci pre |= IS_KABYLAKE(dev_priv) && INTEL_REVID(dev_priv) < 0x1; 18262306a36Sopenharmony_ci pre |= IS_GEMINILAKE(dev_priv) && INTEL_REVID(dev_priv) < 0x3; 18362306a36Sopenharmony_ci pre |= IS_ICELAKE(dev_priv) && INTEL_REVID(dev_priv) < 0x7; 18462306a36Sopenharmony_ci pre |= IS_TIGERLAKE(dev_priv) && INTEL_REVID(dev_priv) < 0x1; 18562306a36Sopenharmony_ci pre |= IS_DG1(dev_priv) && INTEL_REVID(dev_priv) < 0x1; 18662306a36Sopenharmony_ci 18762306a36Sopenharmony_ci if (pre) { 18862306a36Sopenharmony_ci drm_err(&dev_priv->drm, "This is a pre-production stepping. " 18962306a36Sopenharmony_ci "It may not be fully functional.\n"); 19062306a36Sopenharmony_ci add_taint(TAINT_MACHINE_CHECK, LOCKDEP_STILL_OK); 19162306a36Sopenharmony_ci } 19262306a36Sopenharmony_ci} 19362306a36Sopenharmony_ci 19462306a36Sopenharmony_cistatic void sanitize_gpu(struct drm_i915_private *i915) 19562306a36Sopenharmony_ci{ 19662306a36Sopenharmony_ci if (!INTEL_INFO(i915)->gpu_reset_clobbers_display) { 19762306a36Sopenharmony_ci struct intel_gt *gt; 19862306a36Sopenharmony_ci unsigned int i; 19962306a36Sopenharmony_ci 20062306a36Sopenharmony_ci for_each_gt(gt, i915, i) 20162306a36Sopenharmony_ci __intel_gt_reset(gt, ALL_ENGINES); 20262306a36Sopenharmony_ci } 20362306a36Sopenharmony_ci} 20462306a36Sopenharmony_ci 20562306a36Sopenharmony_ci/** 20662306a36Sopenharmony_ci * i915_driver_early_probe - setup state not requiring device access 20762306a36Sopenharmony_ci * @dev_priv: device private 20862306a36Sopenharmony_ci * 20962306a36Sopenharmony_ci * Initialize everything that is a "SW-only" state, that is state not 21062306a36Sopenharmony_ci * requiring accessing the device or exposing the driver via kernel internal 21162306a36Sopenharmony_ci * or userspace interfaces. Example steps belonging here: lock initialization, 21262306a36Sopenharmony_ci * system memory allocation, setting up device specific attributes and 21362306a36Sopenharmony_ci * function hooks not requiring accessing the device. 21462306a36Sopenharmony_ci */ 21562306a36Sopenharmony_cistatic int i915_driver_early_probe(struct drm_i915_private *dev_priv) 21662306a36Sopenharmony_ci{ 21762306a36Sopenharmony_ci int ret = 0; 21862306a36Sopenharmony_ci 21962306a36Sopenharmony_ci if (i915_inject_probe_failure(dev_priv)) 22062306a36Sopenharmony_ci return -ENODEV; 22162306a36Sopenharmony_ci 22262306a36Sopenharmony_ci intel_device_info_runtime_init_early(dev_priv); 22362306a36Sopenharmony_ci 22462306a36Sopenharmony_ci intel_step_init(dev_priv); 22562306a36Sopenharmony_ci 22662306a36Sopenharmony_ci intel_uncore_mmio_debug_init_early(dev_priv); 22762306a36Sopenharmony_ci 22862306a36Sopenharmony_ci spin_lock_init(&dev_priv->irq_lock); 22962306a36Sopenharmony_ci spin_lock_init(&dev_priv->gpu_error.lock); 23062306a36Sopenharmony_ci mutex_init(&dev_priv->display.backlight.lock); 23162306a36Sopenharmony_ci 23262306a36Sopenharmony_ci mutex_init(&dev_priv->sb_lock); 23362306a36Sopenharmony_ci cpu_latency_qos_add_request(&dev_priv->sb_qos, PM_QOS_DEFAULT_VALUE); 23462306a36Sopenharmony_ci 23562306a36Sopenharmony_ci mutex_init(&dev_priv->display.audio.mutex); 23662306a36Sopenharmony_ci mutex_init(&dev_priv->display.wm.wm_mutex); 23762306a36Sopenharmony_ci mutex_init(&dev_priv->display.pps.mutex); 23862306a36Sopenharmony_ci mutex_init(&dev_priv->display.hdcp.hdcp_mutex); 23962306a36Sopenharmony_ci 24062306a36Sopenharmony_ci i915_memcpy_init_early(dev_priv); 24162306a36Sopenharmony_ci intel_runtime_pm_init_early(&dev_priv->runtime_pm); 24262306a36Sopenharmony_ci 24362306a36Sopenharmony_ci ret = i915_workqueues_init(dev_priv); 24462306a36Sopenharmony_ci if (ret < 0) 24562306a36Sopenharmony_ci return ret; 24662306a36Sopenharmony_ci 24762306a36Sopenharmony_ci ret = vlv_suspend_init(dev_priv); 24862306a36Sopenharmony_ci if (ret < 0) 24962306a36Sopenharmony_ci goto err_workqueues; 25062306a36Sopenharmony_ci 25162306a36Sopenharmony_ci ret = intel_region_ttm_device_init(dev_priv); 25262306a36Sopenharmony_ci if (ret) 25362306a36Sopenharmony_ci goto err_ttm; 25462306a36Sopenharmony_ci 25562306a36Sopenharmony_ci ret = intel_root_gt_init_early(dev_priv); 25662306a36Sopenharmony_ci if (ret < 0) 25762306a36Sopenharmony_ci goto err_rootgt; 25862306a36Sopenharmony_ci 25962306a36Sopenharmony_ci i915_gem_init_early(dev_priv); 26062306a36Sopenharmony_ci 26162306a36Sopenharmony_ci /* This must be called before any calls to HAS_PCH_* */ 26262306a36Sopenharmony_ci intel_detect_pch(dev_priv); 26362306a36Sopenharmony_ci 26462306a36Sopenharmony_ci intel_irq_init(dev_priv); 26562306a36Sopenharmony_ci intel_display_driver_early_probe(dev_priv); 26662306a36Sopenharmony_ci intel_clock_gating_hooks_init(dev_priv); 26762306a36Sopenharmony_ci 26862306a36Sopenharmony_ci intel_detect_preproduction_hw(dev_priv); 26962306a36Sopenharmony_ci 27062306a36Sopenharmony_ci return 0; 27162306a36Sopenharmony_ci 27262306a36Sopenharmony_cierr_rootgt: 27362306a36Sopenharmony_ci intel_region_ttm_device_fini(dev_priv); 27462306a36Sopenharmony_cierr_ttm: 27562306a36Sopenharmony_ci vlv_suspend_cleanup(dev_priv); 27662306a36Sopenharmony_cierr_workqueues: 27762306a36Sopenharmony_ci i915_workqueues_cleanup(dev_priv); 27862306a36Sopenharmony_ci return ret; 27962306a36Sopenharmony_ci} 28062306a36Sopenharmony_ci 28162306a36Sopenharmony_ci/** 28262306a36Sopenharmony_ci * i915_driver_late_release - cleanup the setup done in 28362306a36Sopenharmony_ci * i915_driver_early_probe() 28462306a36Sopenharmony_ci * @dev_priv: device private 28562306a36Sopenharmony_ci */ 28662306a36Sopenharmony_cistatic void i915_driver_late_release(struct drm_i915_private *dev_priv) 28762306a36Sopenharmony_ci{ 28862306a36Sopenharmony_ci intel_irq_fini(dev_priv); 28962306a36Sopenharmony_ci intel_power_domains_cleanup(dev_priv); 29062306a36Sopenharmony_ci i915_gem_cleanup_early(dev_priv); 29162306a36Sopenharmony_ci intel_gt_driver_late_release_all(dev_priv); 29262306a36Sopenharmony_ci intel_region_ttm_device_fini(dev_priv); 29362306a36Sopenharmony_ci vlv_suspend_cleanup(dev_priv); 29462306a36Sopenharmony_ci i915_workqueues_cleanup(dev_priv); 29562306a36Sopenharmony_ci 29662306a36Sopenharmony_ci cpu_latency_qos_remove_request(&dev_priv->sb_qos); 29762306a36Sopenharmony_ci mutex_destroy(&dev_priv->sb_lock); 29862306a36Sopenharmony_ci 29962306a36Sopenharmony_ci i915_params_free(&dev_priv->params); 30062306a36Sopenharmony_ci} 30162306a36Sopenharmony_ci 30262306a36Sopenharmony_ci/** 30362306a36Sopenharmony_ci * i915_driver_mmio_probe - setup device MMIO 30462306a36Sopenharmony_ci * @dev_priv: device private 30562306a36Sopenharmony_ci * 30662306a36Sopenharmony_ci * Setup minimal device state necessary for MMIO accesses later in the 30762306a36Sopenharmony_ci * initialization sequence. The setup here should avoid any other device-wide 30862306a36Sopenharmony_ci * side effects or exposing the driver via kernel internal or user space 30962306a36Sopenharmony_ci * interfaces. 31062306a36Sopenharmony_ci */ 31162306a36Sopenharmony_cistatic int i915_driver_mmio_probe(struct drm_i915_private *dev_priv) 31262306a36Sopenharmony_ci{ 31362306a36Sopenharmony_ci struct intel_gt *gt; 31462306a36Sopenharmony_ci int ret, i; 31562306a36Sopenharmony_ci 31662306a36Sopenharmony_ci if (i915_inject_probe_failure(dev_priv)) 31762306a36Sopenharmony_ci return -ENODEV; 31862306a36Sopenharmony_ci 31962306a36Sopenharmony_ci ret = intel_gmch_bridge_setup(dev_priv); 32062306a36Sopenharmony_ci if (ret < 0) 32162306a36Sopenharmony_ci return ret; 32262306a36Sopenharmony_ci 32362306a36Sopenharmony_ci for_each_gt(gt, dev_priv, i) { 32462306a36Sopenharmony_ci ret = intel_uncore_init_mmio(gt->uncore); 32562306a36Sopenharmony_ci if (ret) 32662306a36Sopenharmony_ci return ret; 32762306a36Sopenharmony_ci 32862306a36Sopenharmony_ci ret = drmm_add_action_or_reset(&dev_priv->drm, 32962306a36Sopenharmony_ci intel_uncore_fini_mmio, 33062306a36Sopenharmony_ci gt->uncore); 33162306a36Sopenharmony_ci if (ret) 33262306a36Sopenharmony_ci return ret; 33362306a36Sopenharmony_ci } 33462306a36Sopenharmony_ci 33562306a36Sopenharmony_ci /* Try to make sure MCHBAR is enabled before poking at it */ 33662306a36Sopenharmony_ci intel_gmch_bar_setup(dev_priv); 33762306a36Sopenharmony_ci intel_device_info_runtime_init(dev_priv); 33862306a36Sopenharmony_ci 33962306a36Sopenharmony_ci for_each_gt(gt, dev_priv, i) { 34062306a36Sopenharmony_ci ret = intel_gt_init_mmio(gt); 34162306a36Sopenharmony_ci if (ret) 34262306a36Sopenharmony_ci goto err_uncore; 34362306a36Sopenharmony_ci } 34462306a36Sopenharmony_ci 34562306a36Sopenharmony_ci /* As early as possible, scrub existing GPU state before clobbering */ 34662306a36Sopenharmony_ci sanitize_gpu(dev_priv); 34762306a36Sopenharmony_ci 34862306a36Sopenharmony_ci return 0; 34962306a36Sopenharmony_ci 35062306a36Sopenharmony_cierr_uncore: 35162306a36Sopenharmony_ci intel_gmch_bar_teardown(dev_priv); 35262306a36Sopenharmony_ci 35362306a36Sopenharmony_ci return ret; 35462306a36Sopenharmony_ci} 35562306a36Sopenharmony_ci 35662306a36Sopenharmony_ci/** 35762306a36Sopenharmony_ci * i915_driver_mmio_release - cleanup the setup done in i915_driver_mmio_probe() 35862306a36Sopenharmony_ci * @dev_priv: device private 35962306a36Sopenharmony_ci */ 36062306a36Sopenharmony_cistatic void i915_driver_mmio_release(struct drm_i915_private *dev_priv) 36162306a36Sopenharmony_ci{ 36262306a36Sopenharmony_ci intel_gmch_bar_teardown(dev_priv); 36362306a36Sopenharmony_ci} 36462306a36Sopenharmony_ci 36562306a36Sopenharmony_ci/** 36662306a36Sopenharmony_ci * i915_set_dma_info - set all relevant PCI dma info as configured for the 36762306a36Sopenharmony_ci * platform 36862306a36Sopenharmony_ci * @i915: valid i915 instance 36962306a36Sopenharmony_ci * 37062306a36Sopenharmony_ci * Set the dma max segment size, device and coherent masks. The dma mask set 37162306a36Sopenharmony_ci * needs to occur before i915_ggtt_probe_hw. 37262306a36Sopenharmony_ci * 37362306a36Sopenharmony_ci * A couple of platforms have special needs. Address them as well. 37462306a36Sopenharmony_ci * 37562306a36Sopenharmony_ci */ 37662306a36Sopenharmony_cistatic int i915_set_dma_info(struct drm_i915_private *i915) 37762306a36Sopenharmony_ci{ 37862306a36Sopenharmony_ci unsigned int mask_size = INTEL_INFO(i915)->dma_mask_size; 37962306a36Sopenharmony_ci int ret; 38062306a36Sopenharmony_ci 38162306a36Sopenharmony_ci GEM_BUG_ON(!mask_size); 38262306a36Sopenharmony_ci 38362306a36Sopenharmony_ci /* 38462306a36Sopenharmony_ci * We don't have a max segment size, so set it to the max so sg's 38562306a36Sopenharmony_ci * debugging layer doesn't complain 38662306a36Sopenharmony_ci */ 38762306a36Sopenharmony_ci dma_set_max_seg_size(i915->drm.dev, UINT_MAX); 38862306a36Sopenharmony_ci 38962306a36Sopenharmony_ci ret = dma_set_mask(i915->drm.dev, DMA_BIT_MASK(mask_size)); 39062306a36Sopenharmony_ci if (ret) 39162306a36Sopenharmony_ci goto mask_err; 39262306a36Sopenharmony_ci 39362306a36Sopenharmony_ci /* overlay on gen2 is broken and can't address above 1G */ 39462306a36Sopenharmony_ci if (GRAPHICS_VER(i915) == 2) 39562306a36Sopenharmony_ci mask_size = 30; 39662306a36Sopenharmony_ci 39762306a36Sopenharmony_ci /* 39862306a36Sopenharmony_ci * 965GM sometimes incorrectly writes to hardware status page (HWS) 39962306a36Sopenharmony_ci * using 32bit addressing, overwriting memory if HWS is located 40062306a36Sopenharmony_ci * above 4GB. 40162306a36Sopenharmony_ci * 40262306a36Sopenharmony_ci * The documentation also mentions an issue with undefined 40362306a36Sopenharmony_ci * behaviour if any general state is accessed within a page above 4GB, 40462306a36Sopenharmony_ci * which also needs to be handled carefully. 40562306a36Sopenharmony_ci */ 40662306a36Sopenharmony_ci if (IS_I965G(i915) || IS_I965GM(i915)) 40762306a36Sopenharmony_ci mask_size = 32; 40862306a36Sopenharmony_ci 40962306a36Sopenharmony_ci ret = dma_set_coherent_mask(i915->drm.dev, DMA_BIT_MASK(mask_size)); 41062306a36Sopenharmony_ci if (ret) 41162306a36Sopenharmony_ci goto mask_err; 41262306a36Sopenharmony_ci 41362306a36Sopenharmony_ci return 0; 41462306a36Sopenharmony_ci 41562306a36Sopenharmony_cimask_err: 41662306a36Sopenharmony_ci drm_err(&i915->drm, "Can't set DMA mask/consistent mask (%d)\n", ret); 41762306a36Sopenharmony_ci return ret; 41862306a36Sopenharmony_ci} 41962306a36Sopenharmony_ci 42062306a36Sopenharmony_cistatic int i915_pcode_init(struct drm_i915_private *i915) 42162306a36Sopenharmony_ci{ 42262306a36Sopenharmony_ci struct intel_gt *gt; 42362306a36Sopenharmony_ci int id, ret; 42462306a36Sopenharmony_ci 42562306a36Sopenharmony_ci for_each_gt(gt, i915, id) { 42662306a36Sopenharmony_ci ret = intel_pcode_init(gt->uncore); 42762306a36Sopenharmony_ci if (ret) { 42862306a36Sopenharmony_ci drm_err(>->i915->drm, "gt%d: intel_pcode_init failed %d\n", id, ret); 42962306a36Sopenharmony_ci return ret; 43062306a36Sopenharmony_ci } 43162306a36Sopenharmony_ci } 43262306a36Sopenharmony_ci 43362306a36Sopenharmony_ci return 0; 43462306a36Sopenharmony_ci} 43562306a36Sopenharmony_ci 43662306a36Sopenharmony_ci/** 43762306a36Sopenharmony_ci * i915_driver_hw_probe - setup state requiring device access 43862306a36Sopenharmony_ci * @dev_priv: device private 43962306a36Sopenharmony_ci * 44062306a36Sopenharmony_ci * Setup state that requires accessing the device, but doesn't require 44162306a36Sopenharmony_ci * exposing the driver via kernel internal or userspace interfaces. 44262306a36Sopenharmony_ci */ 44362306a36Sopenharmony_cistatic int i915_driver_hw_probe(struct drm_i915_private *dev_priv) 44462306a36Sopenharmony_ci{ 44562306a36Sopenharmony_ci struct pci_dev *pdev = to_pci_dev(dev_priv->drm.dev); 44662306a36Sopenharmony_ci int ret; 44762306a36Sopenharmony_ci 44862306a36Sopenharmony_ci if (i915_inject_probe_failure(dev_priv)) 44962306a36Sopenharmony_ci return -ENODEV; 45062306a36Sopenharmony_ci 45162306a36Sopenharmony_ci if (HAS_PPGTT(dev_priv)) { 45262306a36Sopenharmony_ci if (intel_vgpu_active(dev_priv) && 45362306a36Sopenharmony_ci !intel_vgpu_has_full_ppgtt(dev_priv)) { 45462306a36Sopenharmony_ci i915_report_error(dev_priv, 45562306a36Sopenharmony_ci "incompatible vGPU found, support for isolated ppGTT required\n"); 45662306a36Sopenharmony_ci return -ENXIO; 45762306a36Sopenharmony_ci } 45862306a36Sopenharmony_ci } 45962306a36Sopenharmony_ci 46062306a36Sopenharmony_ci if (HAS_EXECLISTS(dev_priv)) { 46162306a36Sopenharmony_ci /* 46262306a36Sopenharmony_ci * Older GVT emulation depends upon intercepting CSB mmio, 46362306a36Sopenharmony_ci * which we no longer use, preferring to use the HWSP cache 46462306a36Sopenharmony_ci * instead. 46562306a36Sopenharmony_ci */ 46662306a36Sopenharmony_ci if (intel_vgpu_active(dev_priv) && 46762306a36Sopenharmony_ci !intel_vgpu_has_hwsp_emulation(dev_priv)) { 46862306a36Sopenharmony_ci i915_report_error(dev_priv, 46962306a36Sopenharmony_ci "old vGPU host found, support for HWSP emulation required\n"); 47062306a36Sopenharmony_ci return -ENXIO; 47162306a36Sopenharmony_ci } 47262306a36Sopenharmony_ci } 47362306a36Sopenharmony_ci 47462306a36Sopenharmony_ci /* needs to be done before ggtt probe */ 47562306a36Sopenharmony_ci intel_dram_edram_detect(dev_priv); 47662306a36Sopenharmony_ci 47762306a36Sopenharmony_ci ret = i915_set_dma_info(dev_priv); 47862306a36Sopenharmony_ci if (ret) 47962306a36Sopenharmony_ci return ret; 48062306a36Sopenharmony_ci 48162306a36Sopenharmony_ci ret = i915_perf_init(dev_priv); 48262306a36Sopenharmony_ci if (ret) 48362306a36Sopenharmony_ci return ret; 48462306a36Sopenharmony_ci 48562306a36Sopenharmony_ci ret = i915_ggtt_probe_hw(dev_priv); 48662306a36Sopenharmony_ci if (ret) 48762306a36Sopenharmony_ci goto err_perf; 48862306a36Sopenharmony_ci 48962306a36Sopenharmony_ci ret = drm_aperture_remove_conflicting_pci_framebuffers(pdev, dev_priv->drm.driver); 49062306a36Sopenharmony_ci if (ret) 49162306a36Sopenharmony_ci goto err_ggtt; 49262306a36Sopenharmony_ci 49362306a36Sopenharmony_ci ret = i915_ggtt_init_hw(dev_priv); 49462306a36Sopenharmony_ci if (ret) 49562306a36Sopenharmony_ci goto err_ggtt; 49662306a36Sopenharmony_ci 49762306a36Sopenharmony_ci /* 49862306a36Sopenharmony_ci * Make sure we probe lmem before we probe stolen-lmem. The BAR size 49962306a36Sopenharmony_ci * might be different due to bar resizing. 50062306a36Sopenharmony_ci */ 50162306a36Sopenharmony_ci ret = intel_gt_tiles_init(dev_priv); 50262306a36Sopenharmony_ci if (ret) 50362306a36Sopenharmony_ci goto err_ggtt; 50462306a36Sopenharmony_ci 50562306a36Sopenharmony_ci ret = intel_memory_regions_hw_probe(dev_priv); 50662306a36Sopenharmony_ci if (ret) 50762306a36Sopenharmony_ci goto err_ggtt; 50862306a36Sopenharmony_ci 50962306a36Sopenharmony_ci ret = i915_ggtt_enable_hw(dev_priv); 51062306a36Sopenharmony_ci if (ret) { 51162306a36Sopenharmony_ci drm_err(&dev_priv->drm, "failed to enable GGTT\n"); 51262306a36Sopenharmony_ci goto err_mem_regions; 51362306a36Sopenharmony_ci } 51462306a36Sopenharmony_ci 51562306a36Sopenharmony_ci pci_set_master(pdev); 51662306a36Sopenharmony_ci 51762306a36Sopenharmony_ci /* On the 945G/GM, the chipset reports the MSI capability on the 51862306a36Sopenharmony_ci * integrated graphics even though the support isn't actually there 51962306a36Sopenharmony_ci * according to the published specs. It doesn't appear to function 52062306a36Sopenharmony_ci * correctly in testing on 945G. 52162306a36Sopenharmony_ci * This may be a side effect of MSI having been made available for PEG 52262306a36Sopenharmony_ci * and the registers being closely associated. 52362306a36Sopenharmony_ci * 52462306a36Sopenharmony_ci * According to chipset errata, on the 965GM, MSI interrupts may 52562306a36Sopenharmony_ci * be lost or delayed, and was defeatured. MSI interrupts seem to 52662306a36Sopenharmony_ci * get lost on g4x as well, and interrupt delivery seems to stay 52762306a36Sopenharmony_ci * properly dead afterwards. So we'll just disable them for all 52862306a36Sopenharmony_ci * pre-gen5 chipsets. 52962306a36Sopenharmony_ci * 53062306a36Sopenharmony_ci * dp aux and gmbus irq on gen4 seems to be able to generate legacy 53162306a36Sopenharmony_ci * interrupts even when in MSI mode. This results in spurious 53262306a36Sopenharmony_ci * interrupt warnings if the legacy irq no. is shared with another 53362306a36Sopenharmony_ci * device. The kernel then disables that interrupt source and so 53462306a36Sopenharmony_ci * prevents the other device from working properly. 53562306a36Sopenharmony_ci */ 53662306a36Sopenharmony_ci if (GRAPHICS_VER(dev_priv) >= 5) { 53762306a36Sopenharmony_ci if (pci_enable_msi(pdev) < 0) 53862306a36Sopenharmony_ci drm_dbg(&dev_priv->drm, "can't enable MSI"); 53962306a36Sopenharmony_ci } 54062306a36Sopenharmony_ci 54162306a36Sopenharmony_ci ret = intel_gvt_init(dev_priv); 54262306a36Sopenharmony_ci if (ret) 54362306a36Sopenharmony_ci goto err_msi; 54462306a36Sopenharmony_ci 54562306a36Sopenharmony_ci intel_opregion_setup(dev_priv); 54662306a36Sopenharmony_ci 54762306a36Sopenharmony_ci ret = i915_pcode_init(dev_priv); 54862306a36Sopenharmony_ci if (ret) 54962306a36Sopenharmony_ci goto err_opregion; 55062306a36Sopenharmony_ci 55162306a36Sopenharmony_ci /* 55262306a36Sopenharmony_ci * Fill the dram structure to get the system dram info. This will be 55362306a36Sopenharmony_ci * used for memory latency calculation. 55462306a36Sopenharmony_ci */ 55562306a36Sopenharmony_ci intel_dram_detect(dev_priv); 55662306a36Sopenharmony_ci 55762306a36Sopenharmony_ci intel_bw_init_hw(dev_priv); 55862306a36Sopenharmony_ci 55962306a36Sopenharmony_ci return 0; 56062306a36Sopenharmony_ci 56162306a36Sopenharmony_cierr_opregion: 56262306a36Sopenharmony_ci intel_opregion_cleanup(dev_priv); 56362306a36Sopenharmony_cierr_msi: 56462306a36Sopenharmony_ci if (pdev->msi_enabled) 56562306a36Sopenharmony_ci pci_disable_msi(pdev); 56662306a36Sopenharmony_cierr_mem_regions: 56762306a36Sopenharmony_ci intel_memory_regions_driver_release(dev_priv); 56862306a36Sopenharmony_cierr_ggtt: 56962306a36Sopenharmony_ci i915_ggtt_driver_release(dev_priv); 57062306a36Sopenharmony_ci i915_gem_drain_freed_objects(dev_priv); 57162306a36Sopenharmony_ci i915_ggtt_driver_late_release(dev_priv); 57262306a36Sopenharmony_cierr_perf: 57362306a36Sopenharmony_ci i915_perf_fini(dev_priv); 57462306a36Sopenharmony_ci return ret; 57562306a36Sopenharmony_ci} 57662306a36Sopenharmony_ci 57762306a36Sopenharmony_ci/** 57862306a36Sopenharmony_ci * i915_driver_hw_remove - cleanup the setup done in i915_driver_hw_probe() 57962306a36Sopenharmony_ci * @dev_priv: device private 58062306a36Sopenharmony_ci */ 58162306a36Sopenharmony_cistatic void i915_driver_hw_remove(struct drm_i915_private *dev_priv) 58262306a36Sopenharmony_ci{ 58362306a36Sopenharmony_ci struct pci_dev *pdev = to_pci_dev(dev_priv->drm.dev); 58462306a36Sopenharmony_ci 58562306a36Sopenharmony_ci i915_perf_fini(dev_priv); 58662306a36Sopenharmony_ci 58762306a36Sopenharmony_ci intel_opregion_cleanup(dev_priv); 58862306a36Sopenharmony_ci 58962306a36Sopenharmony_ci if (pdev->msi_enabled) 59062306a36Sopenharmony_ci pci_disable_msi(pdev); 59162306a36Sopenharmony_ci} 59262306a36Sopenharmony_ci 59362306a36Sopenharmony_ci/** 59462306a36Sopenharmony_ci * i915_driver_register - register the driver with the rest of the system 59562306a36Sopenharmony_ci * @dev_priv: device private 59662306a36Sopenharmony_ci * 59762306a36Sopenharmony_ci * Perform any steps necessary to make the driver available via kernel 59862306a36Sopenharmony_ci * internal or userspace interfaces. 59962306a36Sopenharmony_ci */ 60062306a36Sopenharmony_cistatic void i915_driver_register(struct drm_i915_private *dev_priv) 60162306a36Sopenharmony_ci{ 60262306a36Sopenharmony_ci struct intel_gt *gt; 60362306a36Sopenharmony_ci unsigned int i; 60462306a36Sopenharmony_ci 60562306a36Sopenharmony_ci i915_gem_driver_register(dev_priv); 60662306a36Sopenharmony_ci i915_pmu_register(dev_priv); 60762306a36Sopenharmony_ci 60862306a36Sopenharmony_ci intel_vgpu_register(dev_priv); 60962306a36Sopenharmony_ci 61062306a36Sopenharmony_ci /* Reveal our presence to userspace */ 61162306a36Sopenharmony_ci if (drm_dev_register(&dev_priv->drm, 0)) { 61262306a36Sopenharmony_ci drm_err(&dev_priv->drm, 61362306a36Sopenharmony_ci "Failed to register driver for userspace access!\n"); 61462306a36Sopenharmony_ci return; 61562306a36Sopenharmony_ci } 61662306a36Sopenharmony_ci 61762306a36Sopenharmony_ci i915_debugfs_register(dev_priv); 61862306a36Sopenharmony_ci i915_setup_sysfs(dev_priv); 61962306a36Sopenharmony_ci 62062306a36Sopenharmony_ci /* Depends on sysfs having been initialized */ 62162306a36Sopenharmony_ci i915_perf_register(dev_priv); 62262306a36Sopenharmony_ci 62362306a36Sopenharmony_ci for_each_gt(gt, dev_priv, i) 62462306a36Sopenharmony_ci intel_gt_driver_register(gt); 62562306a36Sopenharmony_ci 62662306a36Sopenharmony_ci intel_pxp_debugfs_register(dev_priv->pxp); 62762306a36Sopenharmony_ci 62862306a36Sopenharmony_ci i915_hwmon_register(dev_priv); 62962306a36Sopenharmony_ci 63062306a36Sopenharmony_ci intel_display_driver_register(dev_priv); 63162306a36Sopenharmony_ci 63262306a36Sopenharmony_ci intel_power_domains_enable(dev_priv); 63362306a36Sopenharmony_ci intel_runtime_pm_enable(&dev_priv->runtime_pm); 63462306a36Sopenharmony_ci 63562306a36Sopenharmony_ci intel_register_dsm_handler(); 63662306a36Sopenharmony_ci 63762306a36Sopenharmony_ci if (i915_switcheroo_register(dev_priv)) 63862306a36Sopenharmony_ci drm_err(&dev_priv->drm, "Failed to register vga switcheroo!\n"); 63962306a36Sopenharmony_ci} 64062306a36Sopenharmony_ci 64162306a36Sopenharmony_ci/** 64262306a36Sopenharmony_ci * i915_driver_unregister - cleanup the registration done in i915_driver_regiser() 64362306a36Sopenharmony_ci * @dev_priv: device private 64462306a36Sopenharmony_ci */ 64562306a36Sopenharmony_cistatic void i915_driver_unregister(struct drm_i915_private *dev_priv) 64662306a36Sopenharmony_ci{ 64762306a36Sopenharmony_ci struct intel_gt *gt; 64862306a36Sopenharmony_ci unsigned int i; 64962306a36Sopenharmony_ci 65062306a36Sopenharmony_ci i915_switcheroo_unregister(dev_priv); 65162306a36Sopenharmony_ci 65262306a36Sopenharmony_ci intel_unregister_dsm_handler(); 65362306a36Sopenharmony_ci 65462306a36Sopenharmony_ci intel_runtime_pm_disable(&dev_priv->runtime_pm); 65562306a36Sopenharmony_ci intel_power_domains_disable(dev_priv); 65662306a36Sopenharmony_ci 65762306a36Sopenharmony_ci intel_display_driver_unregister(dev_priv); 65862306a36Sopenharmony_ci 65962306a36Sopenharmony_ci intel_pxp_fini(dev_priv); 66062306a36Sopenharmony_ci 66162306a36Sopenharmony_ci for_each_gt(gt, dev_priv, i) 66262306a36Sopenharmony_ci intel_gt_driver_unregister(gt); 66362306a36Sopenharmony_ci 66462306a36Sopenharmony_ci i915_hwmon_unregister(dev_priv); 66562306a36Sopenharmony_ci 66662306a36Sopenharmony_ci i915_perf_unregister(dev_priv); 66762306a36Sopenharmony_ci i915_pmu_unregister(dev_priv); 66862306a36Sopenharmony_ci 66962306a36Sopenharmony_ci i915_teardown_sysfs(dev_priv); 67062306a36Sopenharmony_ci drm_dev_unplug(&dev_priv->drm); 67162306a36Sopenharmony_ci 67262306a36Sopenharmony_ci i915_gem_driver_unregister(dev_priv); 67362306a36Sopenharmony_ci} 67462306a36Sopenharmony_ci 67562306a36Sopenharmony_civoid 67662306a36Sopenharmony_cii915_print_iommu_status(struct drm_i915_private *i915, struct drm_printer *p) 67762306a36Sopenharmony_ci{ 67862306a36Sopenharmony_ci drm_printf(p, "iommu: %s\n", 67962306a36Sopenharmony_ci str_enabled_disabled(i915_vtd_active(i915))); 68062306a36Sopenharmony_ci} 68162306a36Sopenharmony_ci 68262306a36Sopenharmony_cistatic void i915_welcome_messages(struct drm_i915_private *dev_priv) 68362306a36Sopenharmony_ci{ 68462306a36Sopenharmony_ci if (drm_debug_enabled(DRM_UT_DRIVER)) { 68562306a36Sopenharmony_ci struct drm_printer p = drm_debug_printer("i915 device info:"); 68662306a36Sopenharmony_ci struct intel_gt *gt; 68762306a36Sopenharmony_ci unsigned int i; 68862306a36Sopenharmony_ci 68962306a36Sopenharmony_ci drm_printf(&p, "pciid=0x%04x rev=0x%02x platform=%s (subplatform=0x%x) gen=%i\n", 69062306a36Sopenharmony_ci INTEL_DEVID(dev_priv), 69162306a36Sopenharmony_ci INTEL_REVID(dev_priv), 69262306a36Sopenharmony_ci intel_platform_name(INTEL_INFO(dev_priv)->platform), 69362306a36Sopenharmony_ci intel_subplatform(RUNTIME_INFO(dev_priv), 69462306a36Sopenharmony_ci INTEL_INFO(dev_priv)->platform), 69562306a36Sopenharmony_ci GRAPHICS_VER(dev_priv)); 69662306a36Sopenharmony_ci 69762306a36Sopenharmony_ci intel_device_info_print(INTEL_INFO(dev_priv), 69862306a36Sopenharmony_ci RUNTIME_INFO(dev_priv), &p); 69962306a36Sopenharmony_ci intel_display_device_info_print(DISPLAY_INFO(dev_priv), 70062306a36Sopenharmony_ci DISPLAY_RUNTIME_INFO(dev_priv), &p); 70162306a36Sopenharmony_ci i915_print_iommu_status(dev_priv, &p); 70262306a36Sopenharmony_ci for_each_gt(gt, dev_priv, i) 70362306a36Sopenharmony_ci intel_gt_info_print(>->info, &p); 70462306a36Sopenharmony_ci } 70562306a36Sopenharmony_ci 70662306a36Sopenharmony_ci if (IS_ENABLED(CONFIG_DRM_I915_DEBUG)) 70762306a36Sopenharmony_ci drm_info(&dev_priv->drm, "DRM_I915_DEBUG enabled\n"); 70862306a36Sopenharmony_ci if (IS_ENABLED(CONFIG_DRM_I915_DEBUG_GEM)) 70962306a36Sopenharmony_ci drm_info(&dev_priv->drm, "DRM_I915_DEBUG_GEM enabled\n"); 71062306a36Sopenharmony_ci if (IS_ENABLED(CONFIG_DRM_I915_DEBUG_RUNTIME_PM)) 71162306a36Sopenharmony_ci drm_info(&dev_priv->drm, 71262306a36Sopenharmony_ci "DRM_I915_DEBUG_RUNTIME_PM enabled\n"); 71362306a36Sopenharmony_ci} 71462306a36Sopenharmony_ci 71562306a36Sopenharmony_cistatic struct drm_i915_private * 71662306a36Sopenharmony_cii915_driver_create(struct pci_dev *pdev, const struct pci_device_id *ent) 71762306a36Sopenharmony_ci{ 71862306a36Sopenharmony_ci const struct intel_device_info *match_info = 71962306a36Sopenharmony_ci (struct intel_device_info *)ent->driver_data; 72062306a36Sopenharmony_ci struct drm_i915_private *i915; 72162306a36Sopenharmony_ci 72262306a36Sopenharmony_ci i915 = devm_drm_dev_alloc(&pdev->dev, &i915_drm_driver, 72362306a36Sopenharmony_ci struct drm_i915_private, drm); 72462306a36Sopenharmony_ci if (IS_ERR(i915)) 72562306a36Sopenharmony_ci return i915; 72662306a36Sopenharmony_ci 72762306a36Sopenharmony_ci pci_set_drvdata(pdev, i915); 72862306a36Sopenharmony_ci 72962306a36Sopenharmony_ci /* Device parameters start as a copy of module parameters. */ 73062306a36Sopenharmony_ci i915_params_copy(&i915->params, &i915_modparams); 73162306a36Sopenharmony_ci 73262306a36Sopenharmony_ci /* Set up device info and initial runtime info. */ 73362306a36Sopenharmony_ci intel_device_info_driver_create(i915, pdev->device, match_info); 73462306a36Sopenharmony_ci 73562306a36Sopenharmony_ci return i915; 73662306a36Sopenharmony_ci} 73762306a36Sopenharmony_ci 73862306a36Sopenharmony_ci/** 73962306a36Sopenharmony_ci * i915_driver_probe - setup chip and create an initial config 74062306a36Sopenharmony_ci * @pdev: PCI device 74162306a36Sopenharmony_ci * @ent: matching PCI ID entry 74262306a36Sopenharmony_ci * 74362306a36Sopenharmony_ci * The driver probe routine has to do several things: 74462306a36Sopenharmony_ci * - drive output discovery via intel_display_driver_probe() 74562306a36Sopenharmony_ci * - initialize the memory manager 74662306a36Sopenharmony_ci * - allocate initial config memory 74762306a36Sopenharmony_ci * - setup the DRM framebuffer with the allocated memory 74862306a36Sopenharmony_ci */ 74962306a36Sopenharmony_ciint i915_driver_probe(struct pci_dev *pdev, const struct pci_device_id *ent) 75062306a36Sopenharmony_ci{ 75162306a36Sopenharmony_ci struct drm_i915_private *i915; 75262306a36Sopenharmony_ci int ret; 75362306a36Sopenharmony_ci 75462306a36Sopenharmony_ci ret = pci_enable_device(pdev); 75562306a36Sopenharmony_ci if (ret) { 75662306a36Sopenharmony_ci pr_err("Failed to enable graphics device: %pe\n", ERR_PTR(ret)); 75762306a36Sopenharmony_ci return ret; 75862306a36Sopenharmony_ci } 75962306a36Sopenharmony_ci 76062306a36Sopenharmony_ci i915 = i915_driver_create(pdev, ent); 76162306a36Sopenharmony_ci if (IS_ERR(i915)) { 76262306a36Sopenharmony_ci pci_disable_device(pdev); 76362306a36Sopenharmony_ci return PTR_ERR(i915); 76462306a36Sopenharmony_ci } 76562306a36Sopenharmony_ci 76662306a36Sopenharmony_ci ret = i915_driver_early_probe(i915); 76762306a36Sopenharmony_ci if (ret < 0) 76862306a36Sopenharmony_ci goto out_pci_disable; 76962306a36Sopenharmony_ci 77062306a36Sopenharmony_ci disable_rpm_wakeref_asserts(&i915->runtime_pm); 77162306a36Sopenharmony_ci 77262306a36Sopenharmony_ci intel_vgpu_detect(i915); 77362306a36Sopenharmony_ci 77462306a36Sopenharmony_ci ret = intel_gt_probe_all(i915); 77562306a36Sopenharmony_ci if (ret < 0) 77662306a36Sopenharmony_ci goto out_runtime_pm_put; 77762306a36Sopenharmony_ci 77862306a36Sopenharmony_ci ret = i915_driver_mmio_probe(i915); 77962306a36Sopenharmony_ci if (ret < 0) 78062306a36Sopenharmony_ci goto out_runtime_pm_put; 78162306a36Sopenharmony_ci 78262306a36Sopenharmony_ci ret = i915_driver_hw_probe(i915); 78362306a36Sopenharmony_ci if (ret < 0) 78462306a36Sopenharmony_ci goto out_cleanup_mmio; 78562306a36Sopenharmony_ci 78662306a36Sopenharmony_ci ret = intel_display_driver_probe_noirq(i915); 78762306a36Sopenharmony_ci if (ret < 0) 78862306a36Sopenharmony_ci goto out_cleanup_hw; 78962306a36Sopenharmony_ci 79062306a36Sopenharmony_ci ret = intel_irq_install(i915); 79162306a36Sopenharmony_ci if (ret) 79262306a36Sopenharmony_ci goto out_cleanup_modeset; 79362306a36Sopenharmony_ci 79462306a36Sopenharmony_ci ret = intel_display_driver_probe_nogem(i915); 79562306a36Sopenharmony_ci if (ret) 79662306a36Sopenharmony_ci goto out_cleanup_irq; 79762306a36Sopenharmony_ci 79862306a36Sopenharmony_ci ret = i915_gem_init(i915); 79962306a36Sopenharmony_ci if (ret) 80062306a36Sopenharmony_ci goto out_cleanup_modeset2; 80162306a36Sopenharmony_ci 80262306a36Sopenharmony_ci intel_pxp_init(i915); 80362306a36Sopenharmony_ci 80462306a36Sopenharmony_ci ret = intel_display_driver_probe(i915); 80562306a36Sopenharmony_ci if (ret) 80662306a36Sopenharmony_ci goto out_cleanup_gem; 80762306a36Sopenharmony_ci 80862306a36Sopenharmony_ci i915_driver_register(i915); 80962306a36Sopenharmony_ci 81062306a36Sopenharmony_ci enable_rpm_wakeref_asserts(&i915->runtime_pm); 81162306a36Sopenharmony_ci 81262306a36Sopenharmony_ci i915_welcome_messages(i915); 81362306a36Sopenharmony_ci 81462306a36Sopenharmony_ci i915->do_release = true; 81562306a36Sopenharmony_ci 81662306a36Sopenharmony_ci return 0; 81762306a36Sopenharmony_ci 81862306a36Sopenharmony_ciout_cleanup_gem: 81962306a36Sopenharmony_ci i915_gem_suspend(i915); 82062306a36Sopenharmony_ci i915_gem_driver_remove(i915); 82162306a36Sopenharmony_ci i915_gem_driver_release(i915); 82262306a36Sopenharmony_ciout_cleanup_modeset2: 82362306a36Sopenharmony_ci /* FIXME clean up the error path */ 82462306a36Sopenharmony_ci intel_display_driver_remove(i915); 82562306a36Sopenharmony_ci intel_irq_uninstall(i915); 82662306a36Sopenharmony_ci intel_display_driver_remove_noirq(i915); 82762306a36Sopenharmony_ci goto out_cleanup_modeset; 82862306a36Sopenharmony_ciout_cleanup_irq: 82962306a36Sopenharmony_ci intel_irq_uninstall(i915); 83062306a36Sopenharmony_ciout_cleanup_modeset: 83162306a36Sopenharmony_ci intel_display_driver_remove_nogem(i915); 83262306a36Sopenharmony_ciout_cleanup_hw: 83362306a36Sopenharmony_ci i915_driver_hw_remove(i915); 83462306a36Sopenharmony_ci intel_memory_regions_driver_release(i915); 83562306a36Sopenharmony_ci i915_ggtt_driver_release(i915); 83662306a36Sopenharmony_ci i915_gem_drain_freed_objects(i915); 83762306a36Sopenharmony_ci i915_ggtt_driver_late_release(i915); 83862306a36Sopenharmony_ciout_cleanup_mmio: 83962306a36Sopenharmony_ci i915_driver_mmio_release(i915); 84062306a36Sopenharmony_ciout_runtime_pm_put: 84162306a36Sopenharmony_ci enable_rpm_wakeref_asserts(&i915->runtime_pm); 84262306a36Sopenharmony_ci i915_driver_late_release(i915); 84362306a36Sopenharmony_ciout_pci_disable: 84462306a36Sopenharmony_ci pci_disable_device(pdev); 84562306a36Sopenharmony_ci i915_probe_error(i915, "Device initialization failed (%d)\n", ret); 84662306a36Sopenharmony_ci return ret; 84762306a36Sopenharmony_ci} 84862306a36Sopenharmony_ci 84962306a36Sopenharmony_civoid i915_driver_remove(struct drm_i915_private *i915) 85062306a36Sopenharmony_ci{ 85162306a36Sopenharmony_ci intel_wakeref_t wakeref; 85262306a36Sopenharmony_ci 85362306a36Sopenharmony_ci wakeref = intel_runtime_pm_get(&i915->runtime_pm); 85462306a36Sopenharmony_ci 85562306a36Sopenharmony_ci i915_driver_unregister(i915); 85662306a36Sopenharmony_ci 85762306a36Sopenharmony_ci /* Flush any external code that still may be under the RCU lock */ 85862306a36Sopenharmony_ci synchronize_rcu(); 85962306a36Sopenharmony_ci 86062306a36Sopenharmony_ci i915_gem_suspend(i915); 86162306a36Sopenharmony_ci 86262306a36Sopenharmony_ci intel_gvt_driver_remove(i915); 86362306a36Sopenharmony_ci 86462306a36Sopenharmony_ci intel_display_driver_remove(i915); 86562306a36Sopenharmony_ci 86662306a36Sopenharmony_ci intel_irq_uninstall(i915); 86762306a36Sopenharmony_ci 86862306a36Sopenharmony_ci intel_display_driver_remove_noirq(i915); 86962306a36Sopenharmony_ci 87062306a36Sopenharmony_ci i915_reset_error_state(i915); 87162306a36Sopenharmony_ci i915_gem_driver_remove(i915); 87262306a36Sopenharmony_ci 87362306a36Sopenharmony_ci intel_display_driver_remove_nogem(i915); 87462306a36Sopenharmony_ci 87562306a36Sopenharmony_ci i915_driver_hw_remove(i915); 87662306a36Sopenharmony_ci 87762306a36Sopenharmony_ci intel_runtime_pm_put(&i915->runtime_pm, wakeref); 87862306a36Sopenharmony_ci} 87962306a36Sopenharmony_ci 88062306a36Sopenharmony_cistatic void i915_driver_release(struct drm_device *dev) 88162306a36Sopenharmony_ci{ 88262306a36Sopenharmony_ci struct drm_i915_private *dev_priv = to_i915(dev); 88362306a36Sopenharmony_ci struct intel_runtime_pm *rpm = &dev_priv->runtime_pm; 88462306a36Sopenharmony_ci intel_wakeref_t wakeref; 88562306a36Sopenharmony_ci 88662306a36Sopenharmony_ci if (!dev_priv->do_release) 88762306a36Sopenharmony_ci return; 88862306a36Sopenharmony_ci 88962306a36Sopenharmony_ci wakeref = intel_runtime_pm_get(rpm); 89062306a36Sopenharmony_ci 89162306a36Sopenharmony_ci i915_gem_driver_release(dev_priv); 89262306a36Sopenharmony_ci 89362306a36Sopenharmony_ci intel_memory_regions_driver_release(dev_priv); 89462306a36Sopenharmony_ci i915_ggtt_driver_release(dev_priv); 89562306a36Sopenharmony_ci i915_gem_drain_freed_objects(dev_priv); 89662306a36Sopenharmony_ci i915_ggtt_driver_late_release(dev_priv); 89762306a36Sopenharmony_ci 89862306a36Sopenharmony_ci i915_driver_mmio_release(dev_priv); 89962306a36Sopenharmony_ci 90062306a36Sopenharmony_ci intel_runtime_pm_put(rpm, wakeref); 90162306a36Sopenharmony_ci 90262306a36Sopenharmony_ci intel_runtime_pm_driver_release(rpm); 90362306a36Sopenharmony_ci 90462306a36Sopenharmony_ci i915_driver_late_release(dev_priv); 90562306a36Sopenharmony_ci} 90662306a36Sopenharmony_ci 90762306a36Sopenharmony_cistatic int i915_driver_open(struct drm_device *dev, struct drm_file *file) 90862306a36Sopenharmony_ci{ 90962306a36Sopenharmony_ci struct drm_i915_private *i915 = to_i915(dev); 91062306a36Sopenharmony_ci int ret; 91162306a36Sopenharmony_ci 91262306a36Sopenharmony_ci ret = i915_gem_open(i915, file); 91362306a36Sopenharmony_ci if (ret) 91462306a36Sopenharmony_ci return ret; 91562306a36Sopenharmony_ci 91662306a36Sopenharmony_ci return 0; 91762306a36Sopenharmony_ci} 91862306a36Sopenharmony_ci 91962306a36Sopenharmony_ci/** 92062306a36Sopenharmony_ci * i915_driver_lastclose - clean up after all DRM clients have exited 92162306a36Sopenharmony_ci * @dev: DRM device 92262306a36Sopenharmony_ci * 92362306a36Sopenharmony_ci * Take care of cleaning up after all DRM clients have exited. In the 92462306a36Sopenharmony_ci * mode setting case, we want to restore the kernel's initial mode (just 92562306a36Sopenharmony_ci * in case the last client left us in a bad state). 92662306a36Sopenharmony_ci * 92762306a36Sopenharmony_ci * Additionally, in the non-mode setting case, we'll tear down the GTT 92862306a36Sopenharmony_ci * and DMA structures, since the kernel won't be using them, and clea 92962306a36Sopenharmony_ci * up any GEM state. 93062306a36Sopenharmony_ci */ 93162306a36Sopenharmony_cistatic void i915_driver_lastclose(struct drm_device *dev) 93262306a36Sopenharmony_ci{ 93362306a36Sopenharmony_ci struct drm_i915_private *i915 = to_i915(dev); 93462306a36Sopenharmony_ci 93562306a36Sopenharmony_ci intel_fbdev_restore_mode(i915); 93662306a36Sopenharmony_ci 93762306a36Sopenharmony_ci vga_switcheroo_process_delayed_switch(); 93862306a36Sopenharmony_ci} 93962306a36Sopenharmony_ci 94062306a36Sopenharmony_cistatic void i915_driver_postclose(struct drm_device *dev, struct drm_file *file) 94162306a36Sopenharmony_ci{ 94262306a36Sopenharmony_ci struct drm_i915_file_private *file_priv = file->driver_priv; 94362306a36Sopenharmony_ci 94462306a36Sopenharmony_ci i915_gem_context_close(file); 94562306a36Sopenharmony_ci i915_drm_client_put(file_priv->client); 94662306a36Sopenharmony_ci 94762306a36Sopenharmony_ci kfree_rcu(file_priv, rcu); 94862306a36Sopenharmony_ci 94962306a36Sopenharmony_ci /* Catch up with all the deferred frees from "this" client */ 95062306a36Sopenharmony_ci i915_gem_flush_free_objects(to_i915(dev)); 95162306a36Sopenharmony_ci} 95262306a36Sopenharmony_ci 95362306a36Sopenharmony_cistatic void intel_suspend_encoders(struct drm_i915_private *dev_priv) 95462306a36Sopenharmony_ci{ 95562306a36Sopenharmony_ci struct intel_encoder *encoder; 95662306a36Sopenharmony_ci 95762306a36Sopenharmony_ci if (!HAS_DISPLAY(dev_priv)) 95862306a36Sopenharmony_ci return; 95962306a36Sopenharmony_ci 96062306a36Sopenharmony_ci /* 96162306a36Sopenharmony_ci * TODO: check and remove holding the modeset locks if none of 96262306a36Sopenharmony_ci * the encoders depends on this. 96362306a36Sopenharmony_ci */ 96462306a36Sopenharmony_ci drm_modeset_lock_all(&dev_priv->drm); 96562306a36Sopenharmony_ci for_each_intel_encoder(&dev_priv->drm, encoder) 96662306a36Sopenharmony_ci if (encoder->suspend) 96762306a36Sopenharmony_ci encoder->suspend(encoder); 96862306a36Sopenharmony_ci drm_modeset_unlock_all(&dev_priv->drm); 96962306a36Sopenharmony_ci 97062306a36Sopenharmony_ci for_each_intel_encoder(&dev_priv->drm, encoder) 97162306a36Sopenharmony_ci if (encoder->suspend_complete) 97262306a36Sopenharmony_ci encoder->suspend_complete(encoder); 97362306a36Sopenharmony_ci} 97462306a36Sopenharmony_ci 97562306a36Sopenharmony_cistatic void intel_shutdown_encoders(struct drm_i915_private *dev_priv) 97662306a36Sopenharmony_ci{ 97762306a36Sopenharmony_ci struct intel_encoder *encoder; 97862306a36Sopenharmony_ci 97962306a36Sopenharmony_ci if (!HAS_DISPLAY(dev_priv)) 98062306a36Sopenharmony_ci return; 98162306a36Sopenharmony_ci 98262306a36Sopenharmony_ci /* 98362306a36Sopenharmony_ci * TODO: check and remove holding the modeset locks if none of 98462306a36Sopenharmony_ci * the encoders depends on this. 98562306a36Sopenharmony_ci */ 98662306a36Sopenharmony_ci drm_modeset_lock_all(&dev_priv->drm); 98762306a36Sopenharmony_ci for_each_intel_encoder(&dev_priv->drm, encoder) 98862306a36Sopenharmony_ci if (encoder->shutdown) 98962306a36Sopenharmony_ci encoder->shutdown(encoder); 99062306a36Sopenharmony_ci drm_modeset_unlock_all(&dev_priv->drm); 99162306a36Sopenharmony_ci 99262306a36Sopenharmony_ci for_each_intel_encoder(&dev_priv->drm, encoder) 99362306a36Sopenharmony_ci if (encoder->shutdown_complete) 99462306a36Sopenharmony_ci encoder->shutdown_complete(encoder); 99562306a36Sopenharmony_ci} 99662306a36Sopenharmony_ci 99762306a36Sopenharmony_civoid i915_driver_shutdown(struct drm_i915_private *i915) 99862306a36Sopenharmony_ci{ 99962306a36Sopenharmony_ci disable_rpm_wakeref_asserts(&i915->runtime_pm); 100062306a36Sopenharmony_ci intel_runtime_pm_disable(&i915->runtime_pm); 100162306a36Sopenharmony_ci intel_power_domains_disable(i915); 100262306a36Sopenharmony_ci 100362306a36Sopenharmony_ci if (HAS_DISPLAY(i915)) { 100462306a36Sopenharmony_ci drm_kms_helper_poll_disable(&i915->drm); 100562306a36Sopenharmony_ci 100662306a36Sopenharmony_ci drm_atomic_helper_shutdown(&i915->drm); 100762306a36Sopenharmony_ci } 100862306a36Sopenharmony_ci 100962306a36Sopenharmony_ci intel_dp_mst_suspend(i915); 101062306a36Sopenharmony_ci 101162306a36Sopenharmony_ci intel_runtime_pm_disable_interrupts(i915); 101262306a36Sopenharmony_ci intel_hpd_cancel_work(i915); 101362306a36Sopenharmony_ci 101462306a36Sopenharmony_ci intel_suspend_encoders(i915); 101562306a36Sopenharmony_ci intel_shutdown_encoders(i915); 101662306a36Sopenharmony_ci 101762306a36Sopenharmony_ci intel_dmc_suspend(i915); 101862306a36Sopenharmony_ci 101962306a36Sopenharmony_ci i915_gem_suspend(i915); 102062306a36Sopenharmony_ci 102162306a36Sopenharmony_ci /* 102262306a36Sopenharmony_ci * The only requirement is to reboot with display DC states disabled, 102362306a36Sopenharmony_ci * for now leaving all display power wells in the INIT power domain 102462306a36Sopenharmony_ci * enabled. 102562306a36Sopenharmony_ci * 102662306a36Sopenharmony_ci * TODO: 102762306a36Sopenharmony_ci * - unify the pci_driver::shutdown sequence here with the 102862306a36Sopenharmony_ci * pci_driver.driver.pm.poweroff,poweroff_late sequence. 102962306a36Sopenharmony_ci * - unify the driver remove and system/runtime suspend sequences with 103062306a36Sopenharmony_ci * the above unified shutdown/poweroff sequence. 103162306a36Sopenharmony_ci */ 103262306a36Sopenharmony_ci intel_power_domains_driver_remove(i915); 103362306a36Sopenharmony_ci enable_rpm_wakeref_asserts(&i915->runtime_pm); 103462306a36Sopenharmony_ci 103562306a36Sopenharmony_ci intel_runtime_pm_driver_release(&i915->runtime_pm); 103662306a36Sopenharmony_ci} 103762306a36Sopenharmony_ci 103862306a36Sopenharmony_cistatic bool suspend_to_idle(struct drm_i915_private *dev_priv) 103962306a36Sopenharmony_ci{ 104062306a36Sopenharmony_ci#if IS_ENABLED(CONFIG_ACPI_SLEEP) 104162306a36Sopenharmony_ci if (acpi_target_system_state() < ACPI_STATE_S3) 104262306a36Sopenharmony_ci return true; 104362306a36Sopenharmony_ci#endif 104462306a36Sopenharmony_ci return false; 104562306a36Sopenharmony_ci} 104662306a36Sopenharmony_ci 104762306a36Sopenharmony_cistatic void i915_drm_complete(struct drm_device *dev) 104862306a36Sopenharmony_ci{ 104962306a36Sopenharmony_ci struct drm_i915_private *i915 = to_i915(dev); 105062306a36Sopenharmony_ci 105162306a36Sopenharmony_ci intel_pxp_resume_complete(i915->pxp); 105262306a36Sopenharmony_ci} 105362306a36Sopenharmony_ci 105462306a36Sopenharmony_cistatic int i915_drm_prepare(struct drm_device *dev) 105562306a36Sopenharmony_ci{ 105662306a36Sopenharmony_ci struct drm_i915_private *i915 = to_i915(dev); 105762306a36Sopenharmony_ci 105862306a36Sopenharmony_ci intel_pxp_suspend_prepare(i915->pxp); 105962306a36Sopenharmony_ci 106062306a36Sopenharmony_ci /* 106162306a36Sopenharmony_ci * NB intel_display_driver_suspend() may issue new requests after we've 106262306a36Sopenharmony_ci * ostensibly marked the GPU as ready-to-sleep here. We need to 106362306a36Sopenharmony_ci * split out that work and pull it forward so that after point, 106462306a36Sopenharmony_ci * the GPU is not woken again. 106562306a36Sopenharmony_ci */ 106662306a36Sopenharmony_ci return i915_gem_backup_suspend(i915); 106762306a36Sopenharmony_ci} 106862306a36Sopenharmony_ci 106962306a36Sopenharmony_cistatic int i915_drm_suspend(struct drm_device *dev) 107062306a36Sopenharmony_ci{ 107162306a36Sopenharmony_ci struct drm_i915_private *dev_priv = to_i915(dev); 107262306a36Sopenharmony_ci struct pci_dev *pdev = to_pci_dev(dev_priv->drm.dev); 107362306a36Sopenharmony_ci pci_power_t opregion_target_state; 107462306a36Sopenharmony_ci 107562306a36Sopenharmony_ci disable_rpm_wakeref_asserts(&dev_priv->runtime_pm); 107662306a36Sopenharmony_ci 107762306a36Sopenharmony_ci /* We do a lot of poking in a lot of registers, make sure they work 107862306a36Sopenharmony_ci * properly. */ 107962306a36Sopenharmony_ci intel_power_domains_disable(dev_priv); 108062306a36Sopenharmony_ci if (HAS_DISPLAY(dev_priv)) 108162306a36Sopenharmony_ci drm_kms_helper_poll_disable(dev); 108262306a36Sopenharmony_ci 108362306a36Sopenharmony_ci pci_save_state(pdev); 108462306a36Sopenharmony_ci 108562306a36Sopenharmony_ci intel_display_driver_suspend(dev_priv); 108662306a36Sopenharmony_ci 108762306a36Sopenharmony_ci intel_dp_mst_suspend(dev_priv); 108862306a36Sopenharmony_ci 108962306a36Sopenharmony_ci intel_runtime_pm_disable_interrupts(dev_priv); 109062306a36Sopenharmony_ci intel_hpd_cancel_work(dev_priv); 109162306a36Sopenharmony_ci 109262306a36Sopenharmony_ci intel_suspend_encoders(dev_priv); 109362306a36Sopenharmony_ci 109462306a36Sopenharmony_ci /* Must be called before GGTT is suspended. */ 109562306a36Sopenharmony_ci intel_dpt_suspend(dev_priv); 109662306a36Sopenharmony_ci i915_ggtt_suspend(to_gt(dev_priv)->ggtt); 109762306a36Sopenharmony_ci 109862306a36Sopenharmony_ci i915_save_display(dev_priv); 109962306a36Sopenharmony_ci 110062306a36Sopenharmony_ci opregion_target_state = suspend_to_idle(dev_priv) ? PCI_D1 : PCI_D3cold; 110162306a36Sopenharmony_ci intel_opregion_suspend(dev_priv, opregion_target_state); 110262306a36Sopenharmony_ci 110362306a36Sopenharmony_ci intel_fbdev_set_suspend(dev, FBINFO_STATE_SUSPENDED, true); 110462306a36Sopenharmony_ci 110562306a36Sopenharmony_ci dev_priv->suspend_count++; 110662306a36Sopenharmony_ci 110762306a36Sopenharmony_ci intel_dmc_suspend(dev_priv); 110862306a36Sopenharmony_ci 110962306a36Sopenharmony_ci enable_rpm_wakeref_asserts(&dev_priv->runtime_pm); 111062306a36Sopenharmony_ci 111162306a36Sopenharmony_ci i915_gem_drain_freed_objects(dev_priv); 111262306a36Sopenharmony_ci 111362306a36Sopenharmony_ci return 0; 111462306a36Sopenharmony_ci} 111562306a36Sopenharmony_ci 111662306a36Sopenharmony_cistatic int i915_drm_suspend_late(struct drm_device *dev, bool hibernation) 111762306a36Sopenharmony_ci{ 111862306a36Sopenharmony_ci struct drm_i915_private *dev_priv = to_i915(dev); 111962306a36Sopenharmony_ci struct pci_dev *pdev = to_pci_dev(dev_priv->drm.dev); 112062306a36Sopenharmony_ci struct intel_runtime_pm *rpm = &dev_priv->runtime_pm; 112162306a36Sopenharmony_ci struct intel_gt *gt; 112262306a36Sopenharmony_ci int ret, i; 112362306a36Sopenharmony_ci bool s2idle = !hibernation && suspend_to_idle(dev_priv); 112462306a36Sopenharmony_ci 112562306a36Sopenharmony_ci disable_rpm_wakeref_asserts(rpm); 112662306a36Sopenharmony_ci 112762306a36Sopenharmony_ci intel_pxp_suspend(dev_priv->pxp); 112862306a36Sopenharmony_ci 112962306a36Sopenharmony_ci i915_gem_suspend_late(dev_priv); 113062306a36Sopenharmony_ci 113162306a36Sopenharmony_ci for_each_gt(gt, dev_priv, i) 113262306a36Sopenharmony_ci intel_uncore_suspend(gt->uncore); 113362306a36Sopenharmony_ci 113462306a36Sopenharmony_ci intel_power_domains_suspend(dev_priv, s2idle); 113562306a36Sopenharmony_ci 113662306a36Sopenharmony_ci intel_display_power_suspend_late(dev_priv); 113762306a36Sopenharmony_ci 113862306a36Sopenharmony_ci ret = vlv_suspend_complete(dev_priv); 113962306a36Sopenharmony_ci if (ret) { 114062306a36Sopenharmony_ci drm_err(&dev_priv->drm, "Suspend complete failed: %d\n", ret); 114162306a36Sopenharmony_ci intel_power_domains_resume(dev_priv); 114262306a36Sopenharmony_ci 114362306a36Sopenharmony_ci goto out; 114462306a36Sopenharmony_ci } 114562306a36Sopenharmony_ci 114662306a36Sopenharmony_ci pci_disable_device(pdev); 114762306a36Sopenharmony_ci /* 114862306a36Sopenharmony_ci * During hibernation on some platforms the BIOS may try to access 114962306a36Sopenharmony_ci * the device even though it's already in D3 and hang the machine. So 115062306a36Sopenharmony_ci * leave the device in D0 on those platforms and hope the BIOS will 115162306a36Sopenharmony_ci * power down the device properly. The issue was seen on multiple old 115262306a36Sopenharmony_ci * GENs with different BIOS vendors, so having an explicit blacklist 115362306a36Sopenharmony_ci * is inpractical; apply the workaround on everything pre GEN6. The 115462306a36Sopenharmony_ci * platforms where the issue was seen: 115562306a36Sopenharmony_ci * Lenovo Thinkpad X301, X61s, X60, T60, X41 115662306a36Sopenharmony_ci * Fujitsu FSC S7110 115762306a36Sopenharmony_ci * Acer Aspire 1830T 115862306a36Sopenharmony_ci */ 115962306a36Sopenharmony_ci if (!(hibernation && GRAPHICS_VER(dev_priv) < 6)) 116062306a36Sopenharmony_ci pci_set_power_state(pdev, PCI_D3hot); 116162306a36Sopenharmony_ci 116262306a36Sopenharmony_ciout: 116362306a36Sopenharmony_ci enable_rpm_wakeref_asserts(rpm); 116462306a36Sopenharmony_ci if (!dev_priv->uncore.user_forcewake_count) 116562306a36Sopenharmony_ci intel_runtime_pm_driver_release(rpm); 116662306a36Sopenharmony_ci 116762306a36Sopenharmony_ci return ret; 116862306a36Sopenharmony_ci} 116962306a36Sopenharmony_ci 117062306a36Sopenharmony_ciint i915_driver_suspend_switcheroo(struct drm_i915_private *i915, 117162306a36Sopenharmony_ci pm_message_t state) 117262306a36Sopenharmony_ci{ 117362306a36Sopenharmony_ci int error; 117462306a36Sopenharmony_ci 117562306a36Sopenharmony_ci if (drm_WARN_ON_ONCE(&i915->drm, state.event != PM_EVENT_SUSPEND && 117662306a36Sopenharmony_ci state.event != PM_EVENT_FREEZE)) 117762306a36Sopenharmony_ci return -EINVAL; 117862306a36Sopenharmony_ci 117962306a36Sopenharmony_ci if (i915->drm.switch_power_state == DRM_SWITCH_POWER_OFF) 118062306a36Sopenharmony_ci return 0; 118162306a36Sopenharmony_ci 118262306a36Sopenharmony_ci error = i915_drm_suspend(&i915->drm); 118362306a36Sopenharmony_ci if (error) 118462306a36Sopenharmony_ci return error; 118562306a36Sopenharmony_ci 118662306a36Sopenharmony_ci return i915_drm_suspend_late(&i915->drm, false); 118762306a36Sopenharmony_ci} 118862306a36Sopenharmony_ci 118962306a36Sopenharmony_cistatic int i915_drm_resume(struct drm_device *dev) 119062306a36Sopenharmony_ci{ 119162306a36Sopenharmony_ci struct drm_i915_private *dev_priv = to_i915(dev); 119262306a36Sopenharmony_ci struct intel_gt *gt; 119362306a36Sopenharmony_ci int ret, i; 119462306a36Sopenharmony_ci 119562306a36Sopenharmony_ci disable_rpm_wakeref_asserts(&dev_priv->runtime_pm); 119662306a36Sopenharmony_ci 119762306a36Sopenharmony_ci ret = i915_pcode_init(dev_priv); 119862306a36Sopenharmony_ci if (ret) 119962306a36Sopenharmony_ci return ret; 120062306a36Sopenharmony_ci 120162306a36Sopenharmony_ci sanitize_gpu(dev_priv); 120262306a36Sopenharmony_ci 120362306a36Sopenharmony_ci ret = i915_ggtt_enable_hw(dev_priv); 120462306a36Sopenharmony_ci if (ret) 120562306a36Sopenharmony_ci drm_err(&dev_priv->drm, "failed to re-enable GGTT\n"); 120662306a36Sopenharmony_ci 120762306a36Sopenharmony_ci i915_ggtt_resume(to_gt(dev_priv)->ggtt); 120862306a36Sopenharmony_ci 120962306a36Sopenharmony_ci for_each_gt(gt, dev_priv, i) 121062306a36Sopenharmony_ci if (GRAPHICS_VER(gt->i915) >= 8) 121162306a36Sopenharmony_ci setup_private_pat(gt); 121262306a36Sopenharmony_ci 121362306a36Sopenharmony_ci /* Must be called after GGTT is resumed. */ 121462306a36Sopenharmony_ci intel_dpt_resume(dev_priv); 121562306a36Sopenharmony_ci 121662306a36Sopenharmony_ci intel_dmc_resume(dev_priv); 121762306a36Sopenharmony_ci 121862306a36Sopenharmony_ci i915_restore_display(dev_priv); 121962306a36Sopenharmony_ci intel_pps_unlock_regs_wa(dev_priv); 122062306a36Sopenharmony_ci 122162306a36Sopenharmony_ci intel_init_pch_refclk(dev_priv); 122262306a36Sopenharmony_ci 122362306a36Sopenharmony_ci /* 122462306a36Sopenharmony_ci * Interrupts have to be enabled before any batches are run. If not the 122562306a36Sopenharmony_ci * GPU will hang. i915_gem_init_hw() will initiate batches to 122662306a36Sopenharmony_ci * update/restore the context. 122762306a36Sopenharmony_ci * 122862306a36Sopenharmony_ci * drm_mode_config_reset() needs AUX interrupts. 122962306a36Sopenharmony_ci * 123062306a36Sopenharmony_ci * Modeset enabling in intel_display_driver_init_hw() also needs working 123162306a36Sopenharmony_ci * interrupts. 123262306a36Sopenharmony_ci */ 123362306a36Sopenharmony_ci intel_runtime_pm_enable_interrupts(dev_priv); 123462306a36Sopenharmony_ci 123562306a36Sopenharmony_ci if (HAS_DISPLAY(dev_priv)) 123662306a36Sopenharmony_ci drm_mode_config_reset(dev); 123762306a36Sopenharmony_ci 123862306a36Sopenharmony_ci i915_gem_resume(dev_priv); 123962306a36Sopenharmony_ci 124062306a36Sopenharmony_ci intel_display_driver_init_hw(dev_priv); 124162306a36Sopenharmony_ci 124262306a36Sopenharmony_ci intel_clock_gating_init(dev_priv); 124362306a36Sopenharmony_ci intel_hpd_init(dev_priv); 124462306a36Sopenharmony_ci 124562306a36Sopenharmony_ci /* MST sideband requires HPD interrupts enabled */ 124662306a36Sopenharmony_ci intel_dp_mst_resume(dev_priv); 124762306a36Sopenharmony_ci intel_display_driver_resume(dev_priv); 124862306a36Sopenharmony_ci 124962306a36Sopenharmony_ci intel_hpd_poll_disable(dev_priv); 125062306a36Sopenharmony_ci if (HAS_DISPLAY(dev_priv)) 125162306a36Sopenharmony_ci drm_kms_helper_poll_enable(dev); 125262306a36Sopenharmony_ci 125362306a36Sopenharmony_ci intel_opregion_resume(dev_priv); 125462306a36Sopenharmony_ci 125562306a36Sopenharmony_ci intel_fbdev_set_suspend(dev, FBINFO_STATE_RUNNING, false); 125662306a36Sopenharmony_ci 125762306a36Sopenharmony_ci intel_power_domains_enable(dev_priv); 125862306a36Sopenharmony_ci 125962306a36Sopenharmony_ci intel_gvt_resume(dev_priv); 126062306a36Sopenharmony_ci 126162306a36Sopenharmony_ci enable_rpm_wakeref_asserts(&dev_priv->runtime_pm); 126262306a36Sopenharmony_ci 126362306a36Sopenharmony_ci return 0; 126462306a36Sopenharmony_ci} 126562306a36Sopenharmony_ci 126662306a36Sopenharmony_cistatic int i915_drm_resume_early(struct drm_device *dev) 126762306a36Sopenharmony_ci{ 126862306a36Sopenharmony_ci struct drm_i915_private *dev_priv = to_i915(dev); 126962306a36Sopenharmony_ci struct pci_dev *pdev = to_pci_dev(dev_priv->drm.dev); 127062306a36Sopenharmony_ci struct intel_gt *gt; 127162306a36Sopenharmony_ci int ret, i; 127262306a36Sopenharmony_ci 127362306a36Sopenharmony_ci /* 127462306a36Sopenharmony_ci * We have a resume ordering issue with the snd-hda driver also 127562306a36Sopenharmony_ci * requiring our device to be power up. Due to the lack of a 127662306a36Sopenharmony_ci * parent/child relationship we currently solve this with an early 127762306a36Sopenharmony_ci * resume hook. 127862306a36Sopenharmony_ci * 127962306a36Sopenharmony_ci * FIXME: This should be solved with a special hdmi sink device or 128062306a36Sopenharmony_ci * similar so that power domains can be employed. 128162306a36Sopenharmony_ci */ 128262306a36Sopenharmony_ci 128362306a36Sopenharmony_ci /* 128462306a36Sopenharmony_ci * Note that we need to set the power state explicitly, since we 128562306a36Sopenharmony_ci * powered off the device during freeze and the PCI core won't power 128662306a36Sopenharmony_ci * it back up for us during thaw. Powering off the device during 128762306a36Sopenharmony_ci * freeze is not a hard requirement though, and during the 128862306a36Sopenharmony_ci * suspend/resume phases the PCI core makes sure we get here with the 128962306a36Sopenharmony_ci * device powered on. So in case we change our freeze logic and keep 129062306a36Sopenharmony_ci * the device powered we can also remove the following set power state 129162306a36Sopenharmony_ci * call. 129262306a36Sopenharmony_ci */ 129362306a36Sopenharmony_ci ret = pci_set_power_state(pdev, PCI_D0); 129462306a36Sopenharmony_ci if (ret) { 129562306a36Sopenharmony_ci drm_err(&dev_priv->drm, 129662306a36Sopenharmony_ci "failed to set PCI D0 power state (%d)\n", ret); 129762306a36Sopenharmony_ci return ret; 129862306a36Sopenharmony_ci } 129962306a36Sopenharmony_ci 130062306a36Sopenharmony_ci /* 130162306a36Sopenharmony_ci * Note that pci_enable_device() first enables any parent bridge 130262306a36Sopenharmony_ci * device and only then sets the power state for this device. The 130362306a36Sopenharmony_ci * bridge enabling is a nop though, since bridge devices are resumed 130462306a36Sopenharmony_ci * first. The order of enabling power and enabling the device is 130562306a36Sopenharmony_ci * imposed by the PCI core as described above, so here we preserve the 130662306a36Sopenharmony_ci * same order for the freeze/thaw phases. 130762306a36Sopenharmony_ci * 130862306a36Sopenharmony_ci * TODO: eventually we should remove pci_disable_device() / 130962306a36Sopenharmony_ci * pci_enable_enable_device() from suspend/resume. Due to how they 131062306a36Sopenharmony_ci * depend on the device enable refcount we can't anyway depend on them 131162306a36Sopenharmony_ci * disabling/enabling the device. 131262306a36Sopenharmony_ci */ 131362306a36Sopenharmony_ci if (pci_enable_device(pdev)) 131462306a36Sopenharmony_ci return -EIO; 131562306a36Sopenharmony_ci 131662306a36Sopenharmony_ci pci_set_master(pdev); 131762306a36Sopenharmony_ci 131862306a36Sopenharmony_ci disable_rpm_wakeref_asserts(&dev_priv->runtime_pm); 131962306a36Sopenharmony_ci 132062306a36Sopenharmony_ci ret = vlv_resume_prepare(dev_priv, false); 132162306a36Sopenharmony_ci if (ret) 132262306a36Sopenharmony_ci drm_err(&dev_priv->drm, 132362306a36Sopenharmony_ci "Resume prepare failed: %d, continuing anyway\n", ret); 132462306a36Sopenharmony_ci 132562306a36Sopenharmony_ci for_each_gt(gt, dev_priv, i) { 132662306a36Sopenharmony_ci intel_uncore_resume_early(gt->uncore); 132762306a36Sopenharmony_ci intel_gt_check_and_clear_faults(gt); 132862306a36Sopenharmony_ci } 132962306a36Sopenharmony_ci 133062306a36Sopenharmony_ci intel_display_power_resume_early(dev_priv); 133162306a36Sopenharmony_ci 133262306a36Sopenharmony_ci intel_power_domains_resume(dev_priv); 133362306a36Sopenharmony_ci 133462306a36Sopenharmony_ci enable_rpm_wakeref_asserts(&dev_priv->runtime_pm); 133562306a36Sopenharmony_ci 133662306a36Sopenharmony_ci return ret; 133762306a36Sopenharmony_ci} 133862306a36Sopenharmony_ci 133962306a36Sopenharmony_ciint i915_driver_resume_switcheroo(struct drm_i915_private *i915) 134062306a36Sopenharmony_ci{ 134162306a36Sopenharmony_ci int ret; 134262306a36Sopenharmony_ci 134362306a36Sopenharmony_ci if (i915->drm.switch_power_state == DRM_SWITCH_POWER_OFF) 134462306a36Sopenharmony_ci return 0; 134562306a36Sopenharmony_ci 134662306a36Sopenharmony_ci ret = i915_drm_resume_early(&i915->drm); 134762306a36Sopenharmony_ci if (ret) 134862306a36Sopenharmony_ci return ret; 134962306a36Sopenharmony_ci 135062306a36Sopenharmony_ci return i915_drm_resume(&i915->drm); 135162306a36Sopenharmony_ci} 135262306a36Sopenharmony_ci 135362306a36Sopenharmony_cistatic int i915_pm_prepare(struct device *kdev) 135462306a36Sopenharmony_ci{ 135562306a36Sopenharmony_ci struct drm_i915_private *i915 = kdev_to_i915(kdev); 135662306a36Sopenharmony_ci 135762306a36Sopenharmony_ci if (!i915) { 135862306a36Sopenharmony_ci dev_err(kdev, "DRM not initialized, aborting suspend.\n"); 135962306a36Sopenharmony_ci return -ENODEV; 136062306a36Sopenharmony_ci } 136162306a36Sopenharmony_ci 136262306a36Sopenharmony_ci if (i915->drm.switch_power_state == DRM_SWITCH_POWER_OFF) 136362306a36Sopenharmony_ci return 0; 136462306a36Sopenharmony_ci 136562306a36Sopenharmony_ci return i915_drm_prepare(&i915->drm); 136662306a36Sopenharmony_ci} 136762306a36Sopenharmony_ci 136862306a36Sopenharmony_cistatic int i915_pm_suspend(struct device *kdev) 136962306a36Sopenharmony_ci{ 137062306a36Sopenharmony_ci struct drm_i915_private *i915 = kdev_to_i915(kdev); 137162306a36Sopenharmony_ci 137262306a36Sopenharmony_ci if (!i915) { 137362306a36Sopenharmony_ci dev_err(kdev, "DRM not initialized, aborting suspend.\n"); 137462306a36Sopenharmony_ci return -ENODEV; 137562306a36Sopenharmony_ci } 137662306a36Sopenharmony_ci 137762306a36Sopenharmony_ci if (i915->drm.switch_power_state == DRM_SWITCH_POWER_OFF) 137862306a36Sopenharmony_ci return 0; 137962306a36Sopenharmony_ci 138062306a36Sopenharmony_ci return i915_drm_suspend(&i915->drm); 138162306a36Sopenharmony_ci} 138262306a36Sopenharmony_ci 138362306a36Sopenharmony_cistatic int i915_pm_suspend_late(struct device *kdev) 138462306a36Sopenharmony_ci{ 138562306a36Sopenharmony_ci struct drm_i915_private *i915 = kdev_to_i915(kdev); 138662306a36Sopenharmony_ci 138762306a36Sopenharmony_ci /* 138862306a36Sopenharmony_ci * We have a suspend ordering issue with the snd-hda driver also 138962306a36Sopenharmony_ci * requiring our device to be power up. Due to the lack of a 139062306a36Sopenharmony_ci * parent/child relationship we currently solve this with an late 139162306a36Sopenharmony_ci * suspend hook. 139262306a36Sopenharmony_ci * 139362306a36Sopenharmony_ci * FIXME: This should be solved with a special hdmi sink device or 139462306a36Sopenharmony_ci * similar so that power domains can be employed. 139562306a36Sopenharmony_ci */ 139662306a36Sopenharmony_ci if (i915->drm.switch_power_state == DRM_SWITCH_POWER_OFF) 139762306a36Sopenharmony_ci return 0; 139862306a36Sopenharmony_ci 139962306a36Sopenharmony_ci return i915_drm_suspend_late(&i915->drm, false); 140062306a36Sopenharmony_ci} 140162306a36Sopenharmony_ci 140262306a36Sopenharmony_cistatic int i915_pm_poweroff_late(struct device *kdev) 140362306a36Sopenharmony_ci{ 140462306a36Sopenharmony_ci struct drm_i915_private *i915 = kdev_to_i915(kdev); 140562306a36Sopenharmony_ci 140662306a36Sopenharmony_ci if (i915->drm.switch_power_state == DRM_SWITCH_POWER_OFF) 140762306a36Sopenharmony_ci return 0; 140862306a36Sopenharmony_ci 140962306a36Sopenharmony_ci return i915_drm_suspend_late(&i915->drm, true); 141062306a36Sopenharmony_ci} 141162306a36Sopenharmony_ci 141262306a36Sopenharmony_cistatic int i915_pm_resume_early(struct device *kdev) 141362306a36Sopenharmony_ci{ 141462306a36Sopenharmony_ci struct drm_i915_private *i915 = kdev_to_i915(kdev); 141562306a36Sopenharmony_ci 141662306a36Sopenharmony_ci if (i915->drm.switch_power_state == DRM_SWITCH_POWER_OFF) 141762306a36Sopenharmony_ci return 0; 141862306a36Sopenharmony_ci 141962306a36Sopenharmony_ci return i915_drm_resume_early(&i915->drm); 142062306a36Sopenharmony_ci} 142162306a36Sopenharmony_ci 142262306a36Sopenharmony_cistatic int i915_pm_resume(struct device *kdev) 142362306a36Sopenharmony_ci{ 142462306a36Sopenharmony_ci struct drm_i915_private *i915 = kdev_to_i915(kdev); 142562306a36Sopenharmony_ci 142662306a36Sopenharmony_ci if (i915->drm.switch_power_state == DRM_SWITCH_POWER_OFF) 142762306a36Sopenharmony_ci return 0; 142862306a36Sopenharmony_ci 142962306a36Sopenharmony_ci return i915_drm_resume(&i915->drm); 143062306a36Sopenharmony_ci} 143162306a36Sopenharmony_ci 143262306a36Sopenharmony_cistatic void i915_pm_complete(struct device *kdev) 143362306a36Sopenharmony_ci{ 143462306a36Sopenharmony_ci struct drm_i915_private *i915 = kdev_to_i915(kdev); 143562306a36Sopenharmony_ci 143662306a36Sopenharmony_ci if (i915->drm.switch_power_state == DRM_SWITCH_POWER_OFF) 143762306a36Sopenharmony_ci return; 143862306a36Sopenharmony_ci 143962306a36Sopenharmony_ci i915_drm_complete(&i915->drm); 144062306a36Sopenharmony_ci} 144162306a36Sopenharmony_ci 144262306a36Sopenharmony_ci/* freeze: before creating the hibernation_image */ 144362306a36Sopenharmony_cistatic int i915_pm_freeze(struct device *kdev) 144462306a36Sopenharmony_ci{ 144562306a36Sopenharmony_ci struct drm_i915_private *i915 = kdev_to_i915(kdev); 144662306a36Sopenharmony_ci int ret; 144762306a36Sopenharmony_ci 144862306a36Sopenharmony_ci if (i915->drm.switch_power_state != DRM_SWITCH_POWER_OFF) { 144962306a36Sopenharmony_ci ret = i915_drm_suspend(&i915->drm); 145062306a36Sopenharmony_ci if (ret) 145162306a36Sopenharmony_ci return ret; 145262306a36Sopenharmony_ci } 145362306a36Sopenharmony_ci 145462306a36Sopenharmony_ci ret = i915_gem_freeze(i915); 145562306a36Sopenharmony_ci if (ret) 145662306a36Sopenharmony_ci return ret; 145762306a36Sopenharmony_ci 145862306a36Sopenharmony_ci return 0; 145962306a36Sopenharmony_ci} 146062306a36Sopenharmony_ci 146162306a36Sopenharmony_cistatic int i915_pm_freeze_late(struct device *kdev) 146262306a36Sopenharmony_ci{ 146362306a36Sopenharmony_ci struct drm_i915_private *i915 = kdev_to_i915(kdev); 146462306a36Sopenharmony_ci int ret; 146562306a36Sopenharmony_ci 146662306a36Sopenharmony_ci if (i915->drm.switch_power_state != DRM_SWITCH_POWER_OFF) { 146762306a36Sopenharmony_ci ret = i915_drm_suspend_late(&i915->drm, true); 146862306a36Sopenharmony_ci if (ret) 146962306a36Sopenharmony_ci return ret; 147062306a36Sopenharmony_ci } 147162306a36Sopenharmony_ci 147262306a36Sopenharmony_ci ret = i915_gem_freeze_late(i915); 147362306a36Sopenharmony_ci if (ret) 147462306a36Sopenharmony_ci return ret; 147562306a36Sopenharmony_ci 147662306a36Sopenharmony_ci return 0; 147762306a36Sopenharmony_ci} 147862306a36Sopenharmony_ci 147962306a36Sopenharmony_ci/* thaw: called after creating the hibernation image, but before turning off. */ 148062306a36Sopenharmony_cistatic int i915_pm_thaw_early(struct device *kdev) 148162306a36Sopenharmony_ci{ 148262306a36Sopenharmony_ci return i915_pm_resume_early(kdev); 148362306a36Sopenharmony_ci} 148462306a36Sopenharmony_ci 148562306a36Sopenharmony_cistatic int i915_pm_thaw(struct device *kdev) 148662306a36Sopenharmony_ci{ 148762306a36Sopenharmony_ci return i915_pm_resume(kdev); 148862306a36Sopenharmony_ci} 148962306a36Sopenharmony_ci 149062306a36Sopenharmony_ci/* restore: called after loading the hibernation image. */ 149162306a36Sopenharmony_cistatic int i915_pm_restore_early(struct device *kdev) 149262306a36Sopenharmony_ci{ 149362306a36Sopenharmony_ci return i915_pm_resume_early(kdev); 149462306a36Sopenharmony_ci} 149562306a36Sopenharmony_ci 149662306a36Sopenharmony_cistatic int i915_pm_restore(struct device *kdev) 149762306a36Sopenharmony_ci{ 149862306a36Sopenharmony_ci return i915_pm_resume(kdev); 149962306a36Sopenharmony_ci} 150062306a36Sopenharmony_ci 150162306a36Sopenharmony_cistatic int intel_runtime_suspend(struct device *kdev) 150262306a36Sopenharmony_ci{ 150362306a36Sopenharmony_ci struct drm_i915_private *dev_priv = kdev_to_i915(kdev); 150462306a36Sopenharmony_ci struct intel_runtime_pm *rpm = &dev_priv->runtime_pm; 150562306a36Sopenharmony_ci struct pci_dev *pdev = to_pci_dev(dev_priv->drm.dev); 150662306a36Sopenharmony_ci struct pci_dev *root_pdev; 150762306a36Sopenharmony_ci struct intel_gt *gt; 150862306a36Sopenharmony_ci int ret, i; 150962306a36Sopenharmony_ci 151062306a36Sopenharmony_ci if (drm_WARN_ON_ONCE(&dev_priv->drm, !HAS_RUNTIME_PM(dev_priv))) 151162306a36Sopenharmony_ci return -ENODEV; 151262306a36Sopenharmony_ci 151362306a36Sopenharmony_ci drm_dbg(&dev_priv->drm, "Suspending device\n"); 151462306a36Sopenharmony_ci 151562306a36Sopenharmony_ci disable_rpm_wakeref_asserts(rpm); 151662306a36Sopenharmony_ci 151762306a36Sopenharmony_ci /* 151862306a36Sopenharmony_ci * We are safe here against re-faults, since the fault handler takes 151962306a36Sopenharmony_ci * an RPM reference. 152062306a36Sopenharmony_ci */ 152162306a36Sopenharmony_ci i915_gem_runtime_suspend(dev_priv); 152262306a36Sopenharmony_ci 152362306a36Sopenharmony_ci intel_pxp_runtime_suspend(dev_priv->pxp); 152462306a36Sopenharmony_ci 152562306a36Sopenharmony_ci for_each_gt(gt, dev_priv, i) 152662306a36Sopenharmony_ci intel_gt_runtime_suspend(gt); 152762306a36Sopenharmony_ci 152862306a36Sopenharmony_ci intel_runtime_pm_disable_interrupts(dev_priv); 152962306a36Sopenharmony_ci 153062306a36Sopenharmony_ci for_each_gt(gt, dev_priv, i) 153162306a36Sopenharmony_ci intel_uncore_suspend(gt->uncore); 153262306a36Sopenharmony_ci 153362306a36Sopenharmony_ci intel_display_power_suspend(dev_priv); 153462306a36Sopenharmony_ci 153562306a36Sopenharmony_ci ret = vlv_suspend_complete(dev_priv); 153662306a36Sopenharmony_ci if (ret) { 153762306a36Sopenharmony_ci drm_err(&dev_priv->drm, 153862306a36Sopenharmony_ci "Runtime suspend failed, disabling it (%d)\n", ret); 153962306a36Sopenharmony_ci intel_uncore_runtime_resume(&dev_priv->uncore); 154062306a36Sopenharmony_ci 154162306a36Sopenharmony_ci intel_runtime_pm_enable_interrupts(dev_priv); 154262306a36Sopenharmony_ci 154362306a36Sopenharmony_ci for_each_gt(gt, dev_priv, i) 154462306a36Sopenharmony_ci intel_gt_runtime_resume(gt); 154562306a36Sopenharmony_ci 154662306a36Sopenharmony_ci enable_rpm_wakeref_asserts(rpm); 154762306a36Sopenharmony_ci 154862306a36Sopenharmony_ci return ret; 154962306a36Sopenharmony_ci } 155062306a36Sopenharmony_ci 155162306a36Sopenharmony_ci enable_rpm_wakeref_asserts(rpm); 155262306a36Sopenharmony_ci intel_runtime_pm_driver_release(rpm); 155362306a36Sopenharmony_ci 155462306a36Sopenharmony_ci if (intel_uncore_arm_unclaimed_mmio_detection(&dev_priv->uncore)) 155562306a36Sopenharmony_ci drm_err(&dev_priv->drm, 155662306a36Sopenharmony_ci "Unclaimed access detected prior to suspending\n"); 155762306a36Sopenharmony_ci 155862306a36Sopenharmony_ci /* 155962306a36Sopenharmony_ci * FIXME: Temporary hammer to avoid freezing the machine on our DGFX 156062306a36Sopenharmony_ci * This should be totally removed when we handle the pci states properly 156162306a36Sopenharmony_ci * on runtime PM. 156262306a36Sopenharmony_ci */ 156362306a36Sopenharmony_ci root_pdev = pcie_find_root_port(pdev); 156462306a36Sopenharmony_ci if (root_pdev) 156562306a36Sopenharmony_ci pci_d3cold_disable(root_pdev); 156662306a36Sopenharmony_ci 156762306a36Sopenharmony_ci rpm->suspended = true; 156862306a36Sopenharmony_ci 156962306a36Sopenharmony_ci /* 157062306a36Sopenharmony_ci * FIXME: We really should find a document that references the arguments 157162306a36Sopenharmony_ci * used below! 157262306a36Sopenharmony_ci */ 157362306a36Sopenharmony_ci if (IS_BROADWELL(dev_priv)) { 157462306a36Sopenharmony_ci /* 157562306a36Sopenharmony_ci * On Broadwell, if we use PCI_D1 the PCH DDI ports will stop 157662306a36Sopenharmony_ci * being detected, and the call we do at intel_runtime_resume() 157762306a36Sopenharmony_ci * won't be able to restore them. Since PCI_D3hot matches the 157862306a36Sopenharmony_ci * actual specification and appears to be working, use it. 157962306a36Sopenharmony_ci */ 158062306a36Sopenharmony_ci intel_opregion_notify_adapter(dev_priv, PCI_D3hot); 158162306a36Sopenharmony_ci } else { 158262306a36Sopenharmony_ci /* 158362306a36Sopenharmony_ci * current versions of firmware which depend on this opregion 158462306a36Sopenharmony_ci * notification have repurposed the D1 definition to mean 158562306a36Sopenharmony_ci * "runtime suspended" vs. what you would normally expect (D3) 158662306a36Sopenharmony_ci * to distinguish it from notifications that might be sent via 158762306a36Sopenharmony_ci * the suspend path. 158862306a36Sopenharmony_ci */ 158962306a36Sopenharmony_ci intel_opregion_notify_adapter(dev_priv, PCI_D1); 159062306a36Sopenharmony_ci } 159162306a36Sopenharmony_ci 159262306a36Sopenharmony_ci assert_forcewakes_inactive(&dev_priv->uncore); 159362306a36Sopenharmony_ci 159462306a36Sopenharmony_ci if (!IS_VALLEYVIEW(dev_priv) && !IS_CHERRYVIEW(dev_priv)) 159562306a36Sopenharmony_ci intel_hpd_poll_enable(dev_priv); 159662306a36Sopenharmony_ci 159762306a36Sopenharmony_ci drm_dbg(&dev_priv->drm, "Device suspended\n"); 159862306a36Sopenharmony_ci return 0; 159962306a36Sopenharmony_ci} 160062306a36Sopenharmony_ci 160162306a36Sopenharmony_cistatic int intel_runtime_resume(struct device *kdev) 160262306a36Sopenharmony_ci{ 160362306a36Sopenharmony_ci struct drm_i915_private *dev_priv = kdev_to_i915(kdev); 160462306a36Sopenharmony_ci struct intel_runtime_pm *rpm = &dev_priv->runtime_pm; 160562306a36Sopenharmony_ci struct pci_dev *pdev = to_pci_dev(dev_priv->drm.dev); 160662306a36Sopenharmony_ci struct pci_dev *root_pdev; 160762306a36Sopenharmony_ci struct intel_gt *gt; 160862306a36Sopenharmony_ci int ret, i; 160962306a36Sopenharmony_ci 161062306a36Sopenharmony_ci if (drm_WARN_ON_ONCE(&dev_priv->drm, !HAS_RUNTIME_PM(dev_priv))) 161162306a36Sopenharmony_ci return -ENODEV; 161262306a36Sopenharmony_ci 161362306a36Sopenharmony_ci drm_dbg(&dev_priv->drm, "Resuming device\n"); 161462306a36Sopenharmony_ci 161562306a36Sopenharmony_ci drm_WARN_ON_ONCE(&dev_priv->drm, atomic_read(&rpm->wakeref_count)); 161662306a36Sopenharmony_ci disable_rpm_wakeref_asserts(rpm); 161762306a36Sopenharmony_ci 161862306a36Sopenharmony_ci intel_opregion_notify_adapter(dev_priv, PCI_D0); 161962306a36Sopenharmony_ci rpm->suspended = false; 162062306a36Sopenharmony_ci 162162306a36Sopenharmony_ci root_pdev = pcie_find_root_port(pdev); 162262306a36Sopenharmony_ci if (root_pdev) 162362306a36Sopenharmony_ci pci_d3cold_enable(root_pdev); 162462306a36Sopenharmony_ci 162562306a36Sopenharmony_ci if (intel_uncore_unclaimed_mmio(&dev_priv->uncore)) 162662306a36Sopenharmony_ci drm_dbg(&dev_priv->drm, 162762306a36Sopenharmony_ci "Unclaimed access during suspend, bios?\n"); 162862306a36Sopenharmony_ci 162962306a36Sopenharmony_ci intel_display_power_resume(dev_priv); 163062306a36Sopenharmony_ci 163162306a36Sopenharmony_ci ret = vlv_resume_prepare(dev_priv, true); 163262306a36Sopenharmony_ci 163362306a36Sopenharmony_ci for_each_gt(gt, dev_priv, i) 163462306a36Sopenharmony_ci intel_uncore_runtime_resume(gt->uncore); 163562306a36Sopenharmony_ci 163662306a36Sopenharmony_ci intel_runtime_pm_enable_interrupts(dev_priv); 163762306a36Sopenharmony_ci 163862306a36Sopenharmony_ci /* 163962306a36Sopenharmony_ci * No point of rolling back things in case of an error, as the best 164062306a36Sopenharmony_ci * we can do is to hope that things will still work (and disable RPM). 164162306a36Sopenharmony_ci */ 164262306a36Sopenharmony_ci for_each_gt(gt, dev_priv, i) 164362306a36Sopenharmony_ci intel_gt_runtime_resume(gt); 164462306a36Sopenharmony_ci 164562306a36Sopenharmony_ci intel_pxp_runtime_resume(dev_priv->pxp); 164662306a36Sopenharmony_ci 164762306a36Sopenharmony_ci /* 164862306a36Sopenharmony_ci * On VLV/CHV display interrupts are part of the display 164962306a36Sopenharmony_ci * power well, so hpd is reinitialized from there. For 165062306a36Sopenharmony_ci * everyone else do it here. 165162306a36Sopenharmony_ci */ 165262306a36Sopenharmony_ci if (!IS_VALLEYVIEW(dev_priv) && !IS_CHERRYVIEW(dev_priv)) { 165362306a36Sopenharmony_ci intel_hpd_init(dev_priv); 165462306a36Sopenharmony_ci intel_hpd_poll_disable(dev_priv); 165562306a36Sopenharmony_ci } 165662306a36Sopenharmony_ci 165762306a36Sopenharmony_ci skl_watermark_ipc_update(dev_priv); 165862306a36Sopenharmony_ci 165962306a36Sopenharmony_ci enable_rpm_wakeref_asserts(rpm); 166062306a36Sopenharmony_ci 166162306a36Sopenharmony_ci if (ret) 166262306a36Sopenharmony_ci drm_err(&dev_priv->drm, 166362306a36Sopenharmony_ci "Runtime resume failed, disabling it (%d)\n", ret); 166462306a36Sopenharmony_ci else 166562306a36Sopenharmony_ci drm_dbg(&dev_priv->drm, "Device resumed\n"); 166662306a36Sopenharmony_ci 166762306a36Sopenharmony_ci return ret; 166862306a36Sopenharmony_ci} 166962306a36Sopenharmony_ci 167062306a36Sopenharmony_ciconst struct dev_pm_ops i915_pm_ops = { 167162306a36Sopenharmony_ci /* 167262306a36Sopenharmony_ci * S0ix (via system suspend) and S3 event handlers [PMSG_SUSPEND, 167362306a36Sopenharmony_ci * PMSG_RESUME] 167462306a36Sopenharmony_ci */ 167562306a36Sopenharmony_ci .prepare = i915_pm_prepare, 167662306a36Sopenharmony_ci .suspend = i915_pm_suspend, 167762306a36Sopenharmony_ci .suspend_late = i915_pm_suspend_late, 167862306a36Sopenharmony_ci .resume_early = i915_pm_resume_early, 167962306a36Sopenharmony_ci .resume = i915_pm_resume, 168062306a36Sopenharmony_ci .complete = i915_pm_complete, 168162306a36Sopenharmony_ci 168262306a36Sopenharmony_ci /* 168362306a36Sopenharmony_ci * S4 event handlers 168462306a36Sopenharmony_ci * @freeze, @freeze_late : called (1) before creating the 168562306a36Sopenharmony_ci * hibernation image [PMSG_FREEZE] and 168662306a36Sopenharmony_ci * (2) after rebooting, before restoring 168762306a36Sopenharmony_ci * the image [PMSG_QUIESCE] 168862306a36Sopenharmony_ci * @thaw, @thaw_early : called (1) after creating the hibernation 168962306a36Sopenharmony_ci * image, before writing it [PMSG_THAW] 169062306a36Sopenharmony_ci * and (2) after failing to create or 169162306a36Sopenharmony_ci * restore the image [PMSG_RECOVER] 169262306a36Sopenharmony_ci * @poweroff, @poweroff_late: called after writing the hibernation 169362306a36Sopenharmony_ci * image, before rebooting [PMSG_HIBERNATE] 169462306a36Sopenharmony_ci * @restore, @restore_early : called after rebooting and restoring the 169562306a36Sopenharmony_ci * hibernation image [PMSG_RESTORE] 169662306a36Sopenharmony_ci */ 169762306a36Sopenharmony_ci .freeze = i915_pm_freeze, 169862306a36Sopenharmony_ci .freeze_late = i915_pm_freeze_late, 169962306a36Sopenharmony_ci .thaw_early = i915_pm_thaw_early, 170062306a36Sopenharmony_ci .thaw = i915_pm_thaw, 170162306a36Sopenharmony_ci .poweroff = i915_pm_suspend, 170262306a36Sopenharmony_ci .poweroff_late = i915_pm_poweroff_late, 170362306a36Sopenharmony_ci .restore_early = i915_pm_restore_early, 170462306a36Sopenharmony_ci .restore = i915_pm_restore, 170562306a36Sopenharmony_ci 170662306a36Sopenharmony_ci /* S0ix (via runtime suspend) event handlers */ 170762306a36Sopenharmony_ci .runtime_suspend = intel_runtime_suspend, 170862306a36Sopenharmony_ci .runtime_resume = intel_runtime_resume, 170962306a36Sopenharmony_ci}; 171062306a36Sopenharmony_ci 171162306a36Sopenharmony_cistatic const struct file_operations i915_driver_fops = { 171262306a36Sopenharmony_ci .owner = THIS_MODULE, 171362306a36Sopenharmony_ci .open = drm_open, 171462306a36Sopenharmony_ci .release = drm_release_noglobal, 171562306a36Sopenharmony_ci .unlocked_ioctl = drm_ioctl, 171662306a36Sopenharmony_ci .mmap = i915_gem_mmap, 171762306a36Sopenharmony_ci .poll = drm_poll, 171862306a36Sopenharmony_ci .read = drm_read, 171962306a36Sopenharmony_ci .compat_ioctl = i915_ioc32_compat_ioctl, 172062306a36Sopenharmony_ci .llseek = noop_llseek, 172162306a36Sopenharmony_ci#ifdef CONFIG_PROC_FS 172262306a36Sopenharmony_ci .show_fdinfo = drm_show_fdinfo, 172362306a36Sopenharmony_ci#endif 172462306a36Sopenharmony_ci}; 172562306a36Sopenharmony_ci 172662306a36Sopenharmony_cistatic int 172762306a36Sopenharmony_cii915_gem_reject_pin_ioctl(struct drm_device *dev, void *data, 172862306a36Sopenharmony_ci struct drm_file *file) 172962306a36Sopenharmony_ci{ 173062306a36Sopenharmony_ci return -ENODEV; 173162306a36Sopenharmony_ci} 173262306a36Sopenharmony_ci 173362306a36Sopenharmony_cistatic const struct drm_ioctl_desc i915_ioctls[] = { 173462306a36Sopenharmony_ci DRM_IOCTL_DEF_DRV(I915_INIT, drm_noop, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), 173562306a36Sopenharmony_ci DRM_IOCTL_DEF_DRV(I915_FLUSH, drm_noop, DRM_AUTH), 173662306a36Sopenharmony_ci DRM_IOCTL_DEF_DRV(I915_FLIP, drm_noop, DRM_AUTH), 173762306a36Sopenharmony_ci DRM_IOCTL_DEF_DRV(I915_BATCHBUFFER, drm_noop, DRM_AUTH), 173862306a36Sopenharmony_ci DRM_IOCTL_DEF_DRV(I915_IRQ_EMIT, drm_noop, DRM_AUTH), 173962306a36Sopenharmony_ci DRM_IOCTL_DEF_DRV(I915_IRQ_WAIT, drm_noop, DRM_AUTH), 174062306a36Sopenharmony_ci DRM_IOCTL_DEF_DRV(I915_GETPARAM, i915_getparam_ioctl, DRM_RENDER_ALLOW), 174162306a36Sopenharmony_ci DRM_IOCTL_DEF_DRV(I915_SETPARAM, drm_noop, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), 174262306a36Sopenharmony_ci DRM_IOCTL_DEF_DRV(I915_ALLOC, drm_noop, DRM_AUTH), 174362306a36Sopenharmony_ci DRM_IOCTL_DEF_DRV(I915_FREE, drm_noop, DRM_AUTH), 174462306a36Sopenharmony_ci DRM_IOCTL_DEF_DRV(I915_INIT_HEAP, drm_noop, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), 174562306a36Sopenharmony_ci DRM_IOCTL_DEF_DRV(I915_CMDBUFFER, drm_noop, DRM_AUTH), 174662306a36Sopenharmony_ci DRM_IOCTL_DEF_DRV(I915_DESTROY_HEAP, drm_noop, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), 174762306a36Sopenharmony_ci DRM_IOCTL_DEF_DRV(I915_SET_VBLANK_PIPE, drm_noop, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), 174862306a36Sopenharmony_ci DRM_IOCTL_DEF_DRV(I915_GET_VBLANK_PIPE, drm_noop, DRM_AUTH), 174962306a36Sopenharmony_ci DRM_IOCTL_DEF_DRV(I915_VBLANK_SWAP, drm_noop, DRM_AUTH), 175062306a36Sopenharmony_ci DRM_IOCTL_DEF_DRV(I915_HWS_ADDR, drm_noop, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), 175162306a36Sopenharmony_ci DRM_IOCTL_DEF_DRV(I915_GEM_INIT, drm_noop, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), 175262306a36Sopenharmony_ci DRM_IOCTL_DEF_DRV(I915_GEM_EXECBUFFER, drm_invalid_op, DRM_AUTH), 175362306a36Sopenharmony_ci DRM_IOCTL_DEF_DRV(I915_GEM_EXECBUFFER2_WR, i915_gem_execbuffer2_ioctl, DRM_RENDER_ALLOW), 175462306a36Sopenharmony_ci DRM_IOCTL_DEF_DRV(I915_GEM_PIN, i915_gem_reject_pin_ioctl, DRM_AUTH|DRM_ROOT_ONLY), 175562306a36Sopenharmony_ci DRM_IOCTL_DEF_DRV(I915_GEM_UNPIN, i915_gem_reject_pin_ioctl, DRM_AUTH|DRM_ROOT_ONLY), 175662306a36Sopenharmony_ci DRM_IOCTL_DEF_DRV(I915_GEM_BUSY, i915_gem_busy_ioctl, DRM_RENDER_ALLOW), 175762306a36Sopenharmony_ci DRM_IOCTL_DEF_DRV(I915_GEM_SET_CACHING, i915_gem_set_caching_ioctl, DRM_RENDER_ALLOW), 175862306a36Sopenharmony_ci DRM_IOCTL_DEF_DRV(I915_GEM_GET_CACHING, i915_gem_get_caching_ioctl, DRM_RENDER_ALLOW), 175962306a36Sopenharmony_ci DRM_IOCTL_DEF_DRV(I915_GEM_THROTTLE, i915_gem_throttle_ioctl, DRM_RENDER_ALLOW), 176062306a36Sopenharmony_ci DRM_IOCTL_DEF_DRV(I915_GEM_ENTERVT, drm_noop, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), 176162306a36Sopenharmony_ci DRM_IOCTL_DEF_DRV(I915_GEM_LEAVEVT, drm_noop, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), 176262306a36Sopenharmony_ci DRM_IOCTL_DEF_DRV(I915_GEM_CREATE, i915_gem_create_ioctl, DRM_RENDER_ALLOW), 176362306a36Sopenharmony_ci DRM_IOCTL_DEF_DRV(I915_GEM_CREATE_EXT, i915_gem_create_ext_ioctl, DRM_RENDER_ALLOW), 176462306a36Sopenharmony_ci DRM_IOCTL_DEF_DRV(I915_GEM_PREAD, i915_gem_pread_ioctl, DRM_RENDER_ALLOW), 176562306a36Sopenharmony_ci DRM_IOCTL_DEF_DRV(I915_GEM_PWRITE, i915_gem_pwrite_ioctl, DRM_RENDER_ALLOW), 176662306a36Sopenharmony_ci DRM_IOCTL_DEF_DRV(I915_GEM_MMAP, i915_gem_mmap_ioctl, DRM_RENDER_ALLOW), 176762306a36Sopenharmony_ci DRM_IOCTL_DEF_DRV(I915_GEM_MMAP_OFFSET, i915_gem_mmap_offset_ioctl, DRM_RENDER_ALLOW), 176862306a36Sopenharmony_ci DRM_IOCTL_DEF_DRV(I915_GEM_SET_DOMAIN, i915_gem_set_domain_ioctl, DRM_RENDER_ALLOW), 176962306a36Sopenharmony_ci DRM_IOCTL_DEF_DRV(I915_GEM_SW_FINISH, i915_gem_sw_finish_ioctl, DRM_RENDER_ALLOW), 177062306a36Sopenharmony_ci DRM_IOCTL_DEF_DRV(I915_GEM_SET_TILING, i915_gem_set_tiling_ioctl, DRM_RENDER_ALLOW), 177162306a36Sopenharmony_ci DRM_IOCTL_DEF_DRV(I915_GEM_GET_TILING, i915_gem_get_tiling_ioctl, DRM_RENDER_ALLOW), 177262306a36Sopenharmony_ci DRM_IOCTL_DEF_DRV(I915_GEM_GET_APERTURE, i915_gem_get_aperture_ioctl, DRM_RENDER_ALLOW), 177362306a36Sopenharmony_ci DRM_IOCTL_DEF_DRV(I915_GET_PIPE_FROM_CRTC_ID, intel_get_pipe_from_crtc_id_ioctl, 0), 177462306a36Sopenharmony_ci DRM_IOCTL_DEF_DRV(I915_GEM_MADVISE, i915_gem_madvise_ioctl, DRM_RENDER_ALLOW), 177562306a36Sopenharmony_ci DRM_IOCTL_DEF_DRV(I915_OVERLAY_PUT_IMAGE, intel_overlay_put_image_ioctl, DRM_MASTER), 177662306a36Sopenharmony_ci DRM_IOCTL_DEF_DRV(I915_OVERLAY_ATTRS, intel_overlay_attrs_ioctl, DRM_MASTER), 177762306a36Sopenharmony_ci DRM_IOCTL_DEF_DRV(I915_SET_SPRITE_COLORKEY, intel_sprite_set_colorkey_ioctl, DRM_MASTER), 177862306a36Sopenharmony_ci DRM_IOCTL_DEF_DRV(I915_GET_SPRITE_COLORKEY, drm_noop, DRM_MASTER), 177962306a36Sopenharmony_ci DRM_IOCTL_DEF_DRV(I915_GEM_WAIT, i915_gem_wait_ioctl, DRM_RENDER_ALLOW), 178062306a36Sopenharmony_ci DRM_IOCTL_DEF_DRV(I915_GEM_CONTEXT_CREATE_EXT, i915_gem_context_create_ioctl, DRM_RENDER_ALLOW), 178162306a36Sopenharmony_ci DRM_IOCTL_DEF_DRV(I915_GEM_CONTEXT_DESTROY, i915_gem_context_destroy_ioctl, DRM_RENDER_ALLOW), 178262306a36Sopenharmony_ci DRM_IOCTL_DEF_DRV(I915_REG_READ, i915_reg_read_ioctl, DRM_RENDER_ALLOW), 178362306a36Sopenharmony_ci DRM_IOCTL_DEF_DRV(I915_GET_RESET_STATS, i915_gem_context_reset_stats_ioctl, DRM_RENDER_ALLOW), 178462306a36Sopenharmony_ci DRM_IOCTL_DEF_DRV(I915_GEM_USERPTR, i915_gem_userptr_ioctl, DRM_RENDER_ALLOW), 178562306a36Sopenharmony_ci DRM_IOCTL_DEF_DRV(I915_GEM_CONTEXT_GETPARAM, i915_gem_context_getparam_ioctl, DRM_RENDER_ALLOW), 178662306a36Sopenharmony_ci DRM_IOCTL_DEF_DRV(I915_GEM_CONTEXT_SETPARAM, i915_gem_context_setparam_ioctl, DRM_RENDER_ALLOW), 178762306a36Sopenharmony_ci DRM_IOCTL_DEF_DRV(I915_PERF_OPEN, i915_perf_open_ioctl, DRM_RENDER_ALLOW), 178862306a36Sopenharmony_ci DRM_IOCTL_DEF_DRV(I915_PERF_ADD_CONFIG, i915_perf_add_config_ioctl, DRM_RENDER_ALLOW), 178962306a36Sopenharmony_ci DRM_IOCTL_DEF_DRV(I915_PERF_REMOVE_CONFIG, i915_perf_remove_config_ioctl, DRM_RENDER_ALLOW), 179062306a36Sopenharmony_ci DRM_IOCTL_DEF_DRV(I915_QUERY, i915_query_ioctl, DRM_RENDER_ALLOW), 179162306a36Sopenharmony_ci DRM_IOCTL_DEF_DRV(I915_GEM_VM_CREATE, i915_gem_vm_create_ioctl, DRM_RENDER_ALLOW), 179262306a36Sopenharmony_ci DRM_IOCTL_DEF_DRV(I915_GEM_VM_DESTROY, i915_gem_vm_destroy_ioctl, DRM_RENDER_ALLOW), 179362306a36Sopenharmony_ci}; 179462306a36Sopenharmony_ci 179562306a36Sopenharmony_ci/* 179662306a36Sopenharmony_ci * Interface history: 179762306a36Sopenharmony_ci * 179862306a36Sopenharmony_ci * 1.1: Original. 179962306a36Sopenharmony_ci * 1.2: Add Power Management 180062306a36Sopenharmony_ci * 1.3: Add vblank support 180162306a36Sopenharmony_ci * 1.4: Fix cmdbuffer path, add heap destroy 180262306a36Sopenharmony_ci * 1.5: Add vblank pipe configuration 180362306a36Sopenharmony_ci * 1.6: - New ioctl for scheduling buffer swaps on vertical blank 180462306a36Sopenharmony_ci * - Support vertical blank on secondary display pipe 180562306a36Sopenharmony_ci */ 180662306a36Sopenharmony_ci#define DRIVER_MAJOR 1 180762306a36Sopenharmony_ci#define DRIVER_MINOR 6 180862306a36Sopenharmony_ci#define DRIVER_PATCHLEVEL 0 180962306a36Sopenharmony_ci 181062306a36Sopenharmony_cistatic const struct drm_driver i915_drm_driver = { 181162306a36Sopenharmony_ci /* Don't use MTRRs here; the Xserver or userspace app should 181262306a36Sopenharmony_ci * deal with them for Intel hardware. 181362306a36Sopenharmony_ci */ 181462306a36Sopenharmony_ci .driver_features = 181562306a36Sopenharmony_ci DRIVER_GEM | 181662306a36Sopenharmony_ci DRIVER_RENDER | DRIVER_MODESET | DRIVER_ATOMIC | DRIVER_SYNCOBJ | 181762306a36Sopenharmony_ci DRIVER_SYNCOBJ_TIMELINE, 181862306a36Sopenharmony_ci .release = i915_driver_release, 181962306a36Sopenharmony_ci .open = i915_driver_open, 182062306a36Sopenharmony_ci .lastclose = i915_driver_lastclose, 182162306a36Sopenharmony_ci .postclose = i915_driver_postclose, 182262306a36Sopenharmony_ci .show_fdinfo = PTR_IF(IS_ENABLED(CONFIG_PROC_FS), i915_drm_client_fdinfo), 182362306a36Sopenharmony_ci 182462306a36Sopenharmony_ci .gem_prime_import = i915_gem_prime_import, 182562306a36Sopenharmony_ci 182662306a36Sopenharmony_ci .dumb_create = i915_gem_dumb_create, 182762306a36Sopenharmony_ci .dumb_map_offset = i915_gem_dumb_mmap_offset, 182862306a36Sopenharmony_ci 182962306a36Sopenharmony_ci .ioctls = i915_ioctls, 183062306a36Sopenharmony_ci .num_ioctls = ARRAY_SIZE(i915_ioctls), 183162306a36Sopenharmony_ci .fops = &i915_driver_fops, 183262306a36Sopenharmony_ci .name = DRIVER_NAME, 183362306a36Sopenharmony_ci .desc = DRIVER_DESC, 183462306a36Sopenharmony_ci .date = DRIVER_DATE, 183562306a36Sopenharmony_ci .major = DRIVER_MAJOR, 183662306a36Sopenharmony_ci .minor = DRIVER_MINOR, 183762306a36Sopenharmony_ci .patchlevel = DRIVER_PATCHLEVEL, 183862306a36Sopenharmony_ci}; 1839