18c2ecf20Sopenharmony_ci/* i915_drv.c -- i830,i845,i855,i865,i915 driver -*- linux-c -*- 28c2ecf20Sopenharmony_ci */ 38c2ecf20Sopenharmony_ci/* 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Copyright 2003 Tungsten Graphics, Inc., Cedar Park, Texas. 68c2ecf20Sopenharmony_ci * All Rights Reserved. 78c2ecf20Sopenharmony_ci * 88c2ecf20Sopenharmony_ci * Permission is hereby granted, free of charge, to any person obtaining a 98c2ecf20Sopenharmony_ci * copy of this software and associated documentation files (the 108c2ecf20Sopenharmony_ci * "Software"), to deal in the Software without restriction, including 118c2ecf20Sopenharmony_ci * without limitation the rights to use, copy, modify, merge, publish, 128c2ecf20Sopenharmony_ci * distribute, sub license, and/or sell copies of the Software, and to 138c2ecf20Sopenharmony_ci * permit persons to whom the Software is furnished to do so, subject to 148c2ecf20Sopenharmony_ci * the following conditions: 158c2ecf20Sopenharmony_ci * 168c2ecf20Sopenharmony_ci * The above copyright notice and this permission notice (including the 178c2ecf20Sopenharmony_ci * next paragraph) shall be included in all copies or substantial portions 188c2ecf20Sopenharmony_ci * of the Software. 198c2ecf20Sopenharmony_ci * 208c2ecf20Sopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 218c2ecf20Sopenharmony_ci * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 228c2ecf20Sopenharmony_ci * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. 238c2ecf20Sopenharmony_ci * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR 248c2ecf20Sopenharmony_ci * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 258c2ecf20Sopenharmony_ci * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 268c2ecf20Sopenharmony_ci * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 278c2ecf20Sopenharmony_ci * 288c2ecf20Sopenharmony_ci */ 298c2ecf20Sopenharmony_ci 308c2ecf20Sopenharmony_ci#include <linux/acpi.h> 318c2ecf20Sopenharmony_ci#include <linux/device.h> 328c2ecf20Sopenharmony_ci#include <linux/oom.h> 338c2ecf20Sopenharmony_ci#include <linux/module.h> 348c2ecf20Sopenharmony_ci#include <linux/pci.h> 358c2ecf20Sopenharmony_ci#include <linux/pm.h> 368c2ecf20Sopenharmony_ci#include <linux/pm_runtime.h> 378c2ecf20Sopenharmony_ci#include <linux/pnp.h> 388c2ecf20Sopenharmony_ci#include <linux/slab.h> 398c2ecf20Sopenharmony_ci#include <linux/vga_switcheroo.h> 408c2ecf20Sopenharmony_ci#include <linux/vt.h> 418c2ecf20Sopenharmony_ci#include <acpi/video.h> 428c2ecf20Sopenharmony_ci 438c2ecf20Sopenharmony_ci#include <drm/drm_atomic_helper.h> 448c2ecf20Sopenharmony_ci#include <drm/drm_ioctl.h> 458c2ecf20Sopenharmony_ci#include <drm/drm_irq.h> 468c2ecf20Sopenharmony_ci#include <drm/drm_managed.h> 478c2ecf20Sopenharmony_ci#include <drm/drm_probe_helper.h> 488c2ecf20Sopenharmony_ci 498c2ecf20Sopenharmony_ci#include "display/intel_acpi.h" 508c2ecf20Sopenharmony_ci#include "display/intel_audio.h" 518c2ecf20Sopenharmony_ci#include "display/intel_bw.h" 528c2ecf20Sopenharmony_ci#include "display/intel_cdclk.h" 538c2ecf20Sopenharmony_ci#include "display/intel_csr.h" 548c2ecf20Sopenharmony_ci#include "display/intel_display_debugfs.h" 558c2ecf20Sopenharmony_ci#include "display/intel_display_types.h" 568c2ecf20Sopenharmony_ci#include "display/intel_dp.h" 578c2ecf20Sopenharmony_ci#include "display/intel_fbdev.h" 588c2ecf20Sopenharmony_ci#include "display/intel_hotplug.h" 598c2ecf20Sopenharmony_ci#include "display/intel_overlay.h" 608c2ecf20Sopenharmony_ci#include "display/intel_pipe_crc.h" 618c2ecf20Sopenharmony_ci#include "display/intel_sprite.h" 628c2ecf20Sopenharmony_ci#include "display/intel_vga.h" 638c2ecf20Sopenharmony_ci 648c2ecf20Sopenharmony_ci#include "gem/i915_gem_context.h" 658c2ecf20Sopenharmony_ci#include "gem/i915_gem_ioctls.h" 668c2ecf20Sopenharmony_ci#include "gem/i915_gem_mman.h" 678c2ecf20Sopenharmony_ci#include "gt/intel_gt.h" 688c2ecf20Sopenharmony_ci#include "gt/intel_gt_pm.h" 698c2ecf20Sopenharmony_ci#include "gt/intel_rc6.h" 708c2ecf20Sopenharmony_ci 718c2ecf20Sopenharmony_ci#include "i915_debugfs.h" 728c2ecf20Sopenharmony_ci#include "i915_drv.h" 738c2ecf20Sopenharmony_ci#include "i915_ioc32.h" 748c2ecf20Sopenharmony_ci#include "i915_irq.h" 758c2ecf20Sopenharmony_ci#include "i915_memcpy.h" 768c2ecf20Sopenharmony_ci#include "i915_perf.h" 778c2ecf20Sopenharmony_ci#include "i915_query.h" 788c2ecf20Sopenharmony_ci#include "i915_suspend.h" 798c2ecf20Sopenharmony_ci#include "i915_switcheroo.h" 808c2ecf20Sopenharmony_ci#include "i915_sysfs.h" 818c2ecf20Sopenharmony_ci#include "i915_trace.h" 828c2ecf20Sopenharmony_ci#include "i915_vgpu.h" 838c2ecf20Sopenharmony_ci#include "intel_dram.h" 848c2ecf20Sopenharmony_ci#include "intel_gvt.h" 858c2ecf20Sopenharmony_ci#include "intel_memory_region.h" 868c2ecf20Sopenharmony_ci#include "intel_pm.h" 878c2ecf20Sopenharmony_ci#include "intel_sideband.h" 888c2ecf20Sopenharmony_ci#include "vlv_suspend.h" 898c2ecf20Sopenharmony_ci 908c2ecf20Sopenharmony_cistatic struct drm_driver driver; 918c2ecf20Sopenharmony_ci 928c2ecf20Sopenharmony_cistatic int i915_get_bridge_dev(struct drm_i915_private *dev_priv) 938c2ecf20Sopenharmony_ci{ 948c2ecf20Sopenharmony_ci int domain = pci_domain_nr(dev_priv->drm.pdev->bus); 958c2ecf20Sopenharmony_ci 968c2ecf20Sopenharmony_ci dev_priv->bridge_dev = 978c2ecf20Sopenharmony_ci pci_get_domain_bus_and_slot(domain, 0, PCI_DEVFN(0, 0)); 988c2ecf20Sopenharmony_ci if (!dev_priv->bridge_dev) { 998c2ecf20Sopenharmony_ci drm_err(&dev_priv->drm, "bridge device not found\n"); 1008c2ecf20Sopenharmony_ci return -1; 1018c2ecf20Sopenharmony_ci } 1028c2ecf20Sopenharmony_ci return 0; 1038c2ecf20Sopenharmony_ci} 1048c2ecf20Sopenharmony_ci 1058c2ecf20Sopenharmony_ci/* Allocate space for the MCH regs if needed, return nonzero on error */ 1068c2ecf20Sopenharmony_cistatic int 1078c2ecf20Sopenharmony_ciintel_alloc_mchbar_resource(struct drm_i915_private *dev_priv) 1088c2ecf20Sopenharmony_ci{ 1098c2ecf20Sopenharmony_ci int reg = INTEL_GEN(dev_priv) >= 4 ? MCHBAR_I965 : MCHBAR_I915; 1108c2ecf20Sopenharmony_ci u32 temp_lo, temp_hi = 0; 1118c2ecf20Sopenharmony_ci u64 mchbar_addr; 1128c2ecf20Sopenharmony_ci int ret; 1138c2ecf20Sopenharmony_ci 1148c2ecf20Sopenharmony_ci if (INTEL_GEN(dev_priv) >= 4) 1158c2ecf20Sopenharmony_ci pci_read_config_dword(dev_priv->bridge_dev, reg + 4, &temp_hi); 1168c2ecf20Sopenharmony_ci pci_read_config_dword(dev_priv->bridge_dev, reg, &temp_lo); 1178c2ecf20Sopenharmony_ci mchbar_addr = ((u64)temp_hi << 32) | temp_lo; 1188c2ecf20Sopenharmony_ci 1198c2ecf20Sopenharmony_ci /* If ACPI doesn't have it, assume we need to allocate it ourselves */ 1208c2ecf20Sopenharmony_ci#ifdef CONFIG_PNP 1218c2ecf20Sopenharmony_ci if (mchbar_addr && 1228c2ecf20Sopenharmony_ci pnp_range_reserved(mchbar_addr, mchbar_addr + MCHBAR_SIZE)) 1238c2ecf20Sopenharmony_ci return 0; 1248c2ecf20Sopenharmony_ci#endif 1258c2ecf20Sopenharmony_ci 1268c2ecf20Sopenharmony_ci /* Get some space for it */ 1278c2ecf20Sopenharmony_ci dev_priv->mch_res.name = "i915 MCHBAR"; 1288c2ecf20Sopenharmony_ci dev_priv->mch_res.flags = IORESOURCE_MEM; 1298c2ecf20Sopenharmony_ci ret = pci_bus_alloc_resource(dev_priv->bridge_dev->bus, 1308c2ecf20Sopenharmony_ci &dev_priv->mch_res, 1318c2ecf20Sopenharmony_ci MCHBAR_SIZE, MCHBAR_SIZE, 1328c2ecf20Sopenharmony_ci PCIBIOS_MIN_MEM, 1338c2ecf20Sopenharmony_ci 0, pcibios_align_resource, 1348c2ecf20Sopenharmony_ci dev_priv->bridge_dev); 1358c2ecf20Sopenharmony_ci if (ret) { 1368c2ecf20Sopenharmony_ci drm_dbg(&dev_priv->drm, "failed bus alloc: %d\n", ret); 1378c2ecf20Sopenharmony_ci dev_priv->mch_res.start = 0; 1388c2ecf20Sopenharmony_ci return ret; 1398c2ecf20Sopenharmony_ci } 1408c2ecf20Sopenharmony_ci 1418c2ecf20Sopenharmony_ci if (INTEL_GEN(dev_priv) >= 4) 1428c2ecf20Sopenharmony_ci pci_write_config_dword(dev_priv->bridge_dev, reg + 4, 1438c2ecf20Sopenharmony_ci upper_32_bits(dev_priv->mch_res.start)); 1448c2ecf20Sopenharmony_ci 1458c2ecf20Sopenharmony_ci pci_write_config_dword(dev_priv->bridge_dev, reg, 1468c2ecf20Sopenharmony_ci lower_32_bits(dev_priv->mch_res.start)); 1478c2ecf20Sopenharmony_ci return 0; 1488c2ecf20Sopenharmony_ci} 1498c2ecf20Sopenharmony_ci 1508c2ecf20Sopenharmony_ci/* Setup MCHBAR if possible, return true if we should disable it again */ 1518c2ecf20Sopenharmony_cistatic void 1528c2ecf20Sopenharmony_ciintel_setup_mchbar(struct drm_i915_private *dev_priv) 1538c2ecf20Sopenharmony_ci{ 1548c2ecf20Sopenharmony_ci int mchbar_reg = INTEL_GEN(dev_priv) >= 4 ? MCHBAR_I965 : MCHBAR_I915; 1558c2ecf20Sopenharmony_ci u32 temp; 1568c2ecf20Sopenharmony_ci bool enabled; 1578c2ecf20Sopenharmony_ci 1588c2ecf20Sopenharmony_ci if (IS_VALLEYVIEW(dev_priv) || IS_CHERRYVIEW(dev_priv)) 1598c2ecf20Sopenharmony_ci return; 1608c2ecf20Sopenharmony_ci 1618c2ecf20Sopenharmony_ci dev_priv->mchbar_need_disable = false; 1628c2ecf20Sopenharmony_ci 1638c2ecf20Sopenharmony_ci if (IS_I915G(dev_priv) || IS_I915GM(dev_priv)) { 1648c2ecf20Sopenharmony_ci pci_read_config_dword(dev_priv->bridge_dev, DEVEN, &temp); 1658c2ecf20Sopenharmony_ci enabled = !!(temp & DEVEN_MCHBAR_EN); 1668c2ecf20Sopenharmony_ci } else { 1678c2ecf20Sopenharmony_ci pci_read_config_dword(dev_priv->bridge_dev, mchbar_reg, &temp); 1688c2ecf20Sopenharmony_ci enabled = temp & 1; 1698c2ecf20Sopenharmony_ci } 1708c2ecf20Sopenharmony_ci 1718c2ecf20Sopenharmony_ci /* If it's already enabled, don't have to do anything */ 1728c2ecf20Sopenharmony_ci if (enabled) 1738c2ecf20Sopenharmony_ci return; 1748c2ecf20Sopenharmony_ci 1758c2ecf20Sopenharmony_ci if (intel_alloc_mchbar_resource(dev_priv)) 1768c2ecf20Sopenharmony_ci return; 1778c2ecf20Sopenharmony_ci 1788c2ecf20Sopenharmony_ci dev_priv->mchbar_need_disable = true; 1798c2ecf20Sopenharmony_ci 1808c2ecf20Sopenharmony_ci /* Space is allocated or reserved, so enable it. */ 1818c2ecf20Sopenharmony_ci if (IS_I915G(dev_priv) || IS_I915GM(dev_priv)) { 1828c2ecf20Sopenharmony_ci pci_write_config_dword(dev_priv->bridge_dev, DEVEN, 1838c2ecf20Sopenharmony_ci temp | DEVEN_MCHBAR_EN); 1848c2ecf20Sopenharmony_ci } else { 1858c2ecf20Sopenharmony_ci pci_read_config_dword(dev_priv->bridge_dev, mchbar_reg, &temp); 1868c2ecf20Sopenharmony_ci pci_write_config_dword(dev_priv->bridge_dev, mchbar_reg, temp | 1); 1878c2ecf20Sopenharmony_ci } 1888c2ecf20Sopenharmony_ci} 1898c2ecf20Sopenharmony_ci 1908c2ecf20Sopenharmony_cistatic void 1918c2ecf20Sopenharmony_ciintel_teardown_mchbar(struct drm_i915_private *dev_priv) 1928c2ecf20Sopenharmony_ci{ 1938c2ecf20Sopenharmony_ci int mchbar_reg = INTEL_GEN(dev_priv) >= 4 ? MCHBAR_I965 : MCHBAR_I915; 1948c2ecf20Sopenharmony_ci 1958c2ecf20Sopenharmony_ci if (dev_priv->mchbar_need_disable) { 1968c2ecf20Sopenharmony_ci if (IS_I915G(dev_priv) || IS_I915GM(dev_priv)) { 1978c2ecf20Sopenharmony_ci u32 deven_val; 1988c2ecf20Sopenharmony_ci 1998c2ecf20Sopenharmony_ci pci_read_config_dword(dev_priv->bridge_dev, DEVEN, 2008c2ecf20Sopenharmony_ci &deven_val); 2018c2ecf20Sopenharmony_ci deven_val &= ~DEVEN_MCHBAR_EN; 2028c2ecf20Sopenharmony_ci pci_write_config_dword(dev_priv->bridge_dev, DEVEN, 2038c2ecf20Sopenharmony_ci deven_val); 2048c2ecf20Sopenharmony_ci } else { 2058c2ecf20Sopenharmony_ci u32 mchbar_val; 2068c2ecf20Sopenharmony_ci 2078c2ecf20Sopenharmony_ci pci_read_config_dword(dev_priv->bridge_dev, mchbar_reg, 2088c2ecf20Sopenharmony_ci &mchbar_val); 2098c2ecf20Sopenharmony_ci mchbar_val &= ~1; 2108c2ecf20Sopenharmony_ci pci_write_config_dword(dev_priv->bridge_dev, mchbar_reg, 2118c2ecf20Sopenharmony_ci mchbar_val); 2128c2ecf20Sopenharmony_ci } 2138c2ecf20Sopenharmony_ci } 2148c2ecf20Sopenharmony_ci 2158c2ecf20Sopenharmony_ci if (dev_priv->mch_res.start) 2168c2ecf20Sopenharmony_ci release_resource(&dev_priv->mch_res); 2178c2ecf20Sopenharmony_ci} 2188c2ecf20Sopenharmony_ci 2198c2ecf20Sopenharmony_cistatic int i915_workqueues_init(struct drm_i915_private *dev_priv) 2208c2ecf20Sopenharmony_ci{ 2218c2ecf20Sopenharmony_ci /* 2228c2ecf20Sopenharmony_ci * The i915 workqueue is primarily used for batched retirement of 2238c2ecf20Sopenharmony_ci * requests (and thus managing bo) once the task has been completed 2248c2ecf20Sopenharmony_ci * by the GPU. i915_retire_requests() is called directly when we 2258c2ecf20Sopenharmony_ci * need high-priority retirement, such as waiting for an explicit 2268c2ecf20Sopenharmony_ci * bo. 2278c2ecf20Sopenharmony_ci * 2288c2ecf20Sopenharmony_ci * It is also used for periodic low-priority events, such as 2298c2ecf20Sopenharmony_ci * idle-timers and recording error state. 2308c2ecf20Sopenharmony_ci * 2318c2ecf20Sopenharmony_ci * All tasks on the workqueue are expected to acquire the dev mutex 2328c2ecf20Sopenharmony_ci * so there is no point in running more than one instance of the 2338c2ecf20Sopenharmony_ci * workqueue at any time. Use an ordered one. 2348c2ecf20Sopenharmony_ci */ 2358c2ecf20Sopenharmony_ci dev_priv->wq = alloc_ordered_workqueue("i915", 0); 2368c2ecf20Sopenharmony_ci if (dev_priv->wq == NULL) 2378c2ecf20Sopenharmony_ci goto out_err; 2388c2ecf20Sopenharmony_ci 2398c2ecf20Sopenharmony_ci dev_priv->hotplug.dp_wq = alloc_ordered_workqueue("i915-dp", 0); 2408c2ecf20Sopenharmony_ci if (dev_priv->hotplug.dp_wq == NULL) 2418c2ecf20Sopenharmony_ci goto out_free_wq; 2428c2ecf20Sopenharmony_ci 2438c2ecf20Sopenharmony_ci return 0; 2448c2ecf20Sopenharmony_ci 2458c2ecf20Sopenharmony_ciout_free_wq: 2468c2ecf20Sopenharmony_ci destroy_workqueue(dev_priv->wq); 2478c2ecf20Sopenharmony_ciout_err: 2488c2ecf20Sopenharmony_ci drm_err(&dev_priv->drm, "Failed to allocate workqueues.\n"); 2498c2ecf20Sopenharmony_ci 2508c2ecf20Sopenharmony_ci return -ENOMEM; 2518c2ecf20Sopenharmony_ci} 2528c2ecf20Sopenharmony_ci 2538c2ecf20Sopenharmony_cistatic void i915_workqueues_cleanup(struct drm_i915_private *dev_priv) 2548c2ecf20Sopenharmony_ci{ 2558c2ecf20Sopenharmony_ci destroy_workqueue(dev_priv->hotplug.dp_wq); 2568c2ecf20Sopenharmony_ci destroy_workqueue(dev_priv->wq); 2578c2ecf20Sopenharmony_ci} 2588c2ecf20Sopenharmony_ci 2598c2ecf20Sopenharmony_ci/* 2608c2ecf20Sopenharmony_ci * We don't keep the workarounds for pre-production hardware, so we expect our 2618c2ecf20Sopenharmony_ci * driver to fail on these machines in one way or another. A little warning on 2628c2ecf20Sopenharmony_ci * dmesg may help both the user and the bug triagers. 2638c2ecf20Sopenharmony_ci * 2648c2ecf20Sopenharmony_ci * Our policy for removing pre-production workarounds is to keep the 2658c2ecf20Sopenharmony_ci * current gen workarounds as a guide to the bring-up of the next gen 2668c2ecf20Sopenharmony_ci * (workarounds have a habit of persisting!). Anything older than that 2678c2ecf20Sopenharmony_ci * should be removed along with the complications they introduce. 2688c2ecf20Sopenharmony_ci */ 2698c2ecf20Sopenharmony_cistatic void intel_detect_preproduction_hw(struct drm_i915_private *dev_priv) 2708c2ecf20Sopenharmony_ci{ 2718c2ecf20Sopenharmony_ci bool pre = false; 2728c2ecf20Sopenharmony_ci 2738c2ecf20Sopenharmony_ci pre |= IS_HSW_EARLY_SDV(dev_priv); 2748c2ecf20Sopenharmony_ci pre |= IS_SKL_REVID(dev_priv, 0, SKL_REVID_F0); 2758c2ecf20Sopenharmony_ci pre |= IS_BXT_REVID(dev_priv, 0, BXT_REVID_B_LAST); 2768c2ecf20Sopenharmony_ci pre |= IS_KBL_GT_REVID(dev_priv, 0, KBL_REVID_A0); 2778c2ecf20Sopenharmony_ci pre |= IS_GLK_REVID(dev_priv, 0, GLK_REVID_A2); 2788c2ecf20Sopenharmony_ci 2798c2ecf20Sopenharmony_ci if (pre) { 2808c2ecf20Sopenharmony_ci drm_err(&dev_priv->drm, "This is a pre-production stepping. " 2818c2ecf20Sopenharmony_ci "It may not be fully functional.\n"); 2828c2ecf20Sopenharmony_ci add_taint(TAINT_MACHINE_CHECK, LOCKDEP_STILL_OK); 2838c2ecf20Sopenharmony_ci } 2848c2ecf20Sopenharmony_ci} 2858c2ecf20Sopenharmony_ci 2868c2ecf20Sopenharmony_cistatic void sanitize_gpu(struct drm_i915_private *i915) 2878c2ecf20Sopenharmony_ci{ 2888c2ecf20Sopenharmony_ci if (!INTEL_INFO(i915)->gpu_reset_clobbers_display) 2898c2ecf20Sopenharmony_ci __intel_gt_reset(&i915->gt, ALL_ENGINES); 2908c2ecf20Sopenharmony_ci} 2918c2ecf20Sopenharmony_ci 2928c2ecf20Sopenharmony_ci/** 2938c2ecf20Sopenharmony_ci * i915_driver_early_probe - setup state not requiring device access 2948c2ecf20Sopenharmony_ci * @dev_priv: device private 2958c2ecf20Sopenharmony_ci * 2968c2ecf20Sopenharmony_ci * Initialize everything that is a "SW-only" state, that is state not 2978c2ecf20Sopenharmony_ci * requiring accessing the device or exposing the driver via kernel internal 2988c2ecf20Sopenharmony_ci * or userspace interfaces. Example steps belonging here: lock initialization, 2998c2ecf20Sopenharmony_ci * system memory allocation, setting up device specific attributes and 3008c2ecf20Sopenharmony_ci * function hooks not requiring accessing the device. 3018c2ecf20Sopenharmony_ci */ 3028c2ecf20Sopenharmony_cistatic int i915_driver_early_probe(struct drm_i915_private *dev_priv) 3038c2ecf20Sopenharmony_ci{ 3048c2ecf20Sopenharmony_ci int ret = 0; 3058c2ecf20Sopenharmony_ci 3068c2ecf20Sopenharmony_ci if (i915_inject_probe_failure(dev_priv)) 3078c2ecf20Sopenharmony_ci return -ENODEV; 3088c2ecf20Sopenharmony_ci 3098c2ecf20Sopenharmony_ci intel_device_info_subplatform_init(dev_priv); 3108c2ecf20Sopenharmony_ci 3118c2ecf20Sopenharmony_ci intel_uncore_mmio_debug_init_early(&dev_priv->mmio_debug); 3128c2ecf20Sopenharmony_ci intel_uncore_init_early(&dev_priv->uncore, dev_priv); 3138c2ecf20Sopenharmony_ci 3148c2ecf20Sopenharmony_ci spin_lock_init(&dev_priv->irq_lock); 3158c2ecf20Sopenharmony_ci spin_lock_init(&dev_priv->gpu_error.lock); 3168c2ecf20Sopenharmony_ci mutex_init(&dev_priv->backlight_lock); 3178c2ecf20Sopenharmony_ci 3188c2ecf20Sopenharmony_ci mutex_init(&dev_priv->sb_lock); 3198c2ecf20Sopenharmony_ci cpu_latency_qos_add_request(&dev_priv->sb_qos, PM_QOS_DEFAULT_VALUE); 3208c2ecf20Sopenharmony_ci 3218c2ecf20Sopenharmony_ci mutex_init(&dev_priv->av_mutex); 3228c2ecf20Sopenharmony_ci mutex_init(&dev_priv->wm.wm_mutex); 3238c2ecf20Sopenharmony_ci mutex_init(&dev_priv->pps_mutex); 3248c2ecf20Sopenharmony_ci mutex_init(&dev_priv->hdcp_comp_mutex); 3258c2ecf20Sopenharmony_ci 3268c2ecf20Sopenharmony_ci i915_memcpy_init_early(dev_priv); 3278c2ecf20Sopenharmony_ci intel_runtime_pm_init_early(&dev_priv->runtime_pm); 3288c2ecf20Sopenharmony_ci 3298c2ecf20Sopenharmony_ci ret = i915_workqueues_init(dev_priv); 3308c2ecf20Sopenharmony_ci if (ret < 0) 3318c2ecf20Sopenharmony_ci return ret; 3328c2ecf20Sopenharmony_ci 3338c2ecf20Sopenharmony_ci ret = vlv_suspend_init(dev_priv); 3348c2ecf20Sopenharmony_ci if (ret < 0) 3358c2ecf20Sopenharmony_ci goto err_workqueues; 3368c2ecf20Sopenharmony_ci 3378c2ecf20Sopenharmony_ci intel_wopcm_init_early(&dev_priv->wopcm); 3388c2ecf20Sopenharmony_ci 3398c2ecf20Sopenharmony_ci intel_gt_init_early(&dev_priv->gt, dev_priv); 3408c2ecf20Sopenharmony_ci 3418c2ecf20Sopenharmony_ci i915_gem_init_early(dev_priv); 3428c2ecf20Sopenharmony_ci 3438c2ecf20Sopenharmony_ci /* This must be called before any calls to HAS_PCH_* */ 3448c2ecf20Sopenharmony_ci intel_detect_pch(dev_priv); 3458c2ecf20Sopenharmony_ci 3468c2ecf20Sopenharmony_ci intel_pm_setup(dev_priv); 3478c2ecf20Sopenharmony_ci ret = intel_power_domains_init(dev_priv); 3488c2ecf20Sopenharmony_ci if (ret < 0) 3498c2ecf20Sopenharmony_ci goto err_gem; 3508c2ecf20Sopenharmony_ci intel_irq_init(dev_priv); 3518c2ecf20Sopenharmony_ci intel_init_display_hooks(dev_priv); 3528c2ecf20Sopenharmony_ci intel_init_clock_gating_hooks(dev_priv); 3538c2ecf20Sopenharmony_ci intel_init_audio_hooks(dev_priv); 3548c2ecf20Sopenharmony_ci 3558c2ecf20Sopenharmony_ci intel_detect_preproduction_hw(dev_priv); 3568c2ecf20Sopenharmony_ci 3578c2ecf20Sopenharmony_ci return 0; 3588c2ecf20Sopenharmony_ci 3598c2ecf20Sopenharmony_cierr_gem: 3608c2ecf20Sopenharmony_ci i915_gem_cleanup_early(dev_priv); 3618c2ecf20Sopenharmony_ci intel_gt_driver_late_release(&dev_priv->gt); 3628c2ecf20Sopenharmony_ci vlv_suspend_cleanup(dev_priv); 3638c2ecf20Sopenharmony_cierr_workqueues: 3648c2ecf20Sopenharmony_ci i915_workqueues_cleanup(dev_priv); 3658c2ecf20Sopenharmony_ci return ret; 3668c2ecf20Sopenharmony_ci} 3678c2ecf20Sopenharmony_ci 3688c2ecf20Sopenharmony_ci/** 3698c2ecf20Sopenharmony_ci * i915_driver_late_release - cleanup the setup done in 3708c2ecf20Sopenharmony_ci * i915_driver_early_probe() 3718c2ecf20Sopenharmony_ci * @dev_priv: device private 3728c2ecf20Sopenharmony_ci */ 3738c2ecf20Sopenharmony_cistatic void i915_driver_late_release(struct drm_i915_private *dev_priv) 3748c2ecf20Sopenharmony_ci{ 3758c2ecf20Sopenharmony_ci intel_irq_fini(dev_priv); 3768c2ecf20Sopenharmony_ci intel_power_domains_cleanup(dev_priv); 3778c2ecf20Sopenharmony_ci i915_gem_cleanup_early(dev_priv); 3788c2ecf20Sopenharmony_ci intel_gt_driver_late_release(&dev_priv->gt); 3798c2ecf20Sopenharmony_ci vlv_suspend_cleanup(dev_priv); 3808c2ecf20Sopenharmony_ci i915_workqueues_cleanup(dev_priv); 3818c2ecf20Sopenharmony_ci 3828c2ecf20Sopenharmony_ci cpu_latency_qos_remove_request(&dev_priv->sb_qos); 3838c2ecf20Sopenharmony_ci mutex_destroy(&dev_priv->sb_lock); 3848c2ecf20Sopenharmony_ci 3858c2ecf20Sopenharmony_ci i915_params_free(&dev_priv->params); 3868c2ecf20Sopenharmony_ci} 3878c2ecf20Sopenharmony_ci 3888c2ecf20Sopenharmony_ci/** 3898c2ecf20Sopenharmony_ci * i915_driver_mmio_probe - setup device MMIO 3908c2ecf20Sopenharmony_ci * @dev_priv: device private 3918c2ecf20Sopenharmony_ci * 3928c2ecf20Sopenharmony_ci * Setup minimal device state necessary for MMIO accesses later in the 3938c2ecf20Sopenharmony_ci * initialization sequence. The setup here should avoid any other device-wide 3948c2ecf20Sopenharmony_ci * side effects or exposing the driver via kernel internal or user space 3958c2ecf20Sopenharmony_ci * interfaces. 3968c2ecf20Sopenharmony_ci */ 3978c2ecf20Sopenharmony_cistatic int i915_driver_mmio_probe(struct drm_i915_private *dev_priv) 3988c2ecf20Sopenharmony_ci{ 3998c2ecf20Sopenharmony_ci int ret; 4008c2ecf20Sopenharmony_ci 4018c2ecf20Sopenharmony_ci if (i915_inject_probe_failure(dev_priv)) 4028c2ecf20Sopenharmony_ci return -ENODEV; 4038c2ecf20Sopenharmony_ci 4048c2ecf20Sopenharmony_ci if (i915_get_bridge_dev(dev_priv)) 4058c2ecf20Sopenharmony_ci return -EIO; 4068c2ecf20Sopenharmony_ci 4078c2ecf20Sopenharmony_ci ret = intel_uncore_init_mmio(&dev_priv->uncore); 4088c2ecf20Sopenharmony_ci if (ret < 0) 4098c2ecf20Sopenharmony_ci goto err_bridge; 4108c2ecf20Sopenharmony_ci 4118c2ecf20Sopenharmony_ci /* Try to make sure MCHBAR is enabled before poking at it */ 4128c2ecf20Sopenharmony_ci intel_setup_mchbar(dev_priv); 4138c2ecf20Sopenharmony_ci 4148c2ecf20Sopenharmony_ci ret = intel_gt_init_mmio(&dev_priv->gt); 4158c2ecf20Sopenharmony_ci if (ret) 4168c2ecf20Sopenharmony_ci goto err_uncore; 4178c2ecf20Sopenharmony_ci 4188c2ecf20Sopenharmony_ci /* As early as possible, scrub existing GPU state before clobbering */ 4198c2ecf20Sopenharmony_ci sanitize_gpu(dev_priv); 4208c2ecf20Sopenharmony_ci 4218c2ecf20Sopenharmony_ci return 0; 4228c2ecf20Sopenharmony_ci 4238c2ecf20Sopenharmony_cierr_uncore: 4248c2ecf20Sopenharmony_ci intel_teardown_mchbar(dev_priv); 4258c2ecf20Sopenharmony_ci intel_uncore_fini_mmio(&dev_priv->uncore); 4268c2ecf20Sopenharmony_cierr_bridge: 4278c2ecf20Sopenharmony_ci pci_dev_put(dev_priv->bridge_dev); 4288c2ecf20Sopenharmony_ci 4298c2ecf20Sopenharmony_ci return ret; 4308c2ecf20Sopenharmony_ci} 4318c2ecf20Sopenharmony_ci 4328c2ecf20Sopenharmony_ci/** 4338c2ecf20Sopenharmony_ci * i915_driver_mmio_release - cleanup the setup done in i915_driver_mmio_probe() 4348c2ecf20Sopenharmony_ci * @dev_priv: device private 4358c2ecf20Sopenharmony_ci */ 4368c2ecf20Sopenharmony_cistatic void i915_driver_mmio_release(struct drm_i915_private *dev_priv) 4378c2ecf20Sopenharmony_ci{ 4388c2ecf20Sopenharmony_ci intel_teardown_mchbar(dev_priv); 4398c2ecf20Sopenharmony_ci intel_uncore_fini_mmio(&dev_priv->uncore); 4408c2ecf20Sopenharmony_ci pci_dev_put(dev_priv->bridge_dev); 4418c2ecf20Sopenharmony_ci} 4428c2ecf20Sopenharmony_ci 4438c2ecf20Sopenharmony_cistatic void intel_sanitize_options(struct drm_i915_private *dev_priv) 4448c2ecf20Sopenharmony_ci{ 4458c2ecf20Sopenharmony_ci intel_gvt_sanitize_options(dev_priv); 4468c2ecf20Sopenharmony_ci} 4478c2ecf20Sopenharmony_ci 4488c2ecf20Sopenharmony_ci/** 4498c2ecf20Sopenharmony_ci * i915_set_dma_info - set all relevant PCI dma info as configured for the 4508c2ecf20Sopenharmony_ci * platform 4518c2ecf20Sopenharmony_ci * @i915: valid i915 instance 4528c2ecf20Sopenharmony_ci * 4538c2ecf20Sopenharmony_ci * Set the dma max segment size, device and coherent masks. The dma mask set 4548c2ecf20Sopenharmony_ci * needs to occur before i915_ggtt_probe_hw. 4558c2ecf20Sopenharmony_ci * 4568c2ecf20Sopenharmony_ci * A couple of platforms have special needs. Address them as well. 4578c2ecf20Sopenharmony_ci * 4588c2ecf20Sopenharmony_ci */ 4598c2ecf20Sopenharmony_cistatic int i915_set_dma_info(struct drm_i915_private *i915) 4608c2ecf20Sopenharmony_ci{ 4618c2ecf20Sopenharmony_ci struct pci_dev *pdev = i915->drm.pdev; 4628c2ecf20Sopenharmony_ci unsigned int mask_size = INTEL_INFO(i915)->dma_mask_size; 4638c2ecf20Sopenharmony_ci int ret; 4648c2ecf20Sopenharmony_ci 4658c2ecf20Sopenharmony_ci GEM_BUG_ON(!mask_size); 4668c2ecf20Sopenharmony_ci 4678c2ecf20Sopenharmony_ci /* 4688c2ecf20Sopenharmony_ci * We don't have a max segment size, so set it to the max so sg's 4698c2ecf20Sopenharmony_ci * debugging layer doesn't complain 4708c2ecf20Sopenharmony_ci */ 4718c2ecf20Sopenharmony_ci dma_set_max_seg_size(&pdev->dev, UINT_MAX); 4728c2ecf20Sopenharmony_ci 4738c2ecf20Sopenharmony_ci ret = dma_set_mask(&pdev->dev, DMA_BIT_MASK(mask_size)); 4748c2ecf20Sopenharmony_ci if (ret) 4758c2ecf20Sopenharmony_ci goto mask_err; 4768c2ecf20Sopenharmony_ci 4778c2ecf20Sopenharmony_ci /* overlay on gen2 is broken and can't address above 1G */ 4788c2ecf20Sopenharmony_ci if (IS_GEN(i915, 2)) 4798c2ecf20Sopenharmony_ci mask_size = 30; 4808c2ecf20Sopenharmony_ci 4818c2ecf20Sopenharmony_ci /* 4828c2ecf20Sopenharmony_ci * 965GM sometimes incorrectly writes to hardware status page (HWS) 4838c2ecf20Sopenharmony_ci * using 32bit addressing, overwriting memory if HWS is located 4848c2ecf20Sopenharmony_ci * above 4GB. 4858c2ecf20Sopenharmony_ci * 4868c2ecf20Sopenharmony_ci * The documentation also mentions an issue with undefined 4878c2ecf20Sopenharmony_ci * behaviour if any general state is accessed within a page above 4GB, 4888c2ecf20Sopenharmony_ci * which also needs to be handled carefully. 4898c2ecf20Sopenharmony_ci */ 4908c2ecf20Sopenharmony_ci if (IS_I965G(i915) || IS_I965GM(i915)) 4918c2ecf20Sopenharmony_ci mask_size = 32; 4928c2ecf20Sopenharmony_ci 4938c2ecf20Sopenharmony_ci ret = dma_set_coherent_mask(&pdev->dev, DMA_BIT_MASK(mask_size)); 4948c2ecf20Sopenharmony_ci if (ret) 4958c2ecf20Sopenharmony_ci goto mask_err; 4968c2ecf20Sopenharmony_ci 4978c2ecf20Sopenharmony_ci return 0; 4988c2ecf20Sopenharmony_ci 4998c2ecf20Sopenharmony_cimask_err: 5008c2ecf20Sopenharmony_ci drm_err(&i915->drm, "Can't set DMA mask/consistent mask (%d)\n", ret); 5018c2ecf20Sopenharmony_ci return ret; 5028c2ecf20Sopenharmony_ci} 5038c2ecf20Sopenharmony_ci 5048c2ecf20Sopenharmony_ci/** 5058c2ecf20Sopenharmony_ci * i915_driver_hw_probe - setup state requiring device access 5068c2ecf20Sopenharmony_ci * @dev_priv: device private 5078c2ecf20Sopenharmony_ci * 5088c2ecf20Sopenharmony_ci * Setup state that requires accessing the device, but doesn't require 5098c2ecf20Sopenharmony_ci * exposing the driver via kernel internal or userspace interfaces. 5108c2ecf20Sopenharmony_ci */ 5118c2ecf20Sopenharmony_cistatic int i915_driver_hw_probe(struct drm_i915_private *dev_priv) 5128c2ecf20Sopenharmony_ci{ 5138c2ecf20Sopenharmony_ci struct pci_dev *pdev = dev_priv->drm.pdev; 5148c2ecf20Sopenharmony_ci int ret; 5158c2ecf20Sopenharmony_ci 5168c2ecf20Sopenharmony_ci if (i915_inject_probe_failure(dev_priv)) 5178c2ecf20Sopenharmony_ci return -ENODEV; 5188c2ecf20Sopenharmony_ci 5198c2ecf20Sopenharmony_ci intel_device_info_runtime_init(dev_priv); 5208c2ecf20Sopenharmony_ci 5218c2ecf20Sopenharmony_ci if (HAS_PPGTT(dev_priv)) { 5228c2ecf20Sopenharmony_ci if (intel_vgpu_active(dev_priv) && 5238c2ecf20Sopenharmony_ci !intel_vgpu_has_full_ppgtt(dev_priv)) { 5248c2ecf20Sopenharmony_ci i915_report_error(dev_priv, 5258c2ecf20Sopenharmony_ci "incompatible vGPU found, support for isolated ppGTT required\n"); 5268c2ecf20Sopenharmony_ci return -ENXIO; 5278c2ecf20Sopenharmony_ci } 5288c2ecf20Sopenharmony_ci } 5298c2ecf20Sopenharmony_ci 5308c2ecf20Sopenharmony_ci if (HAS_EXECLISTS(dev_priv)) { 5318c2ecf20Sopenharmony_ci /* 5328c2ecf20Sopenharmony_ci * Older GVT emulation depends upon intercepting CSB mmio, 5338c2ecf20Sopenharmony_ci * which we no longer use, preferring to use the HWSP cache 5348c2ecf20Sopenharmony_ci * instead. 5358c2ecf20Sopenharmony_ci */ 5368c2ecf20Sopenharmony_ci if (intel_vgpu_active(dev_priv) && 5378c2ecf20Sopenharmony_ci !intel_vgpu_has_hwsp_emulation(dev_priv)) { 5388c2ecf20Sopenharmony_ci i915_report_error(dev_priv, 5398c2ecf20Sopenharmony_ci "old vGPU host found, support for HWSP emulation required\n"); 5408c2ecf20Sopenharmony_ci return -ENXIO; 5418c2ecf20Sopenharmony_ci } 5428c2ecf20Sopenharmony_ci } 5438c2ecf20Sopenharmony_ci 5448c2ecf20Sopenharmony_ci intel_sanitize_options(dev_priv); 5458c2ecf20Sopenharmony_ci 5468c2ecf20Sopenharmony_ci /* needs to be done before ggtt probe */ 5478c2ecf20Sopenharmony_ci intel_dram_edram_detect(dev_priv); 5488c2ecf20Sopenharmony_ci 5498c2ecf20Sopenharmony_ci ret = i915_set_dma_info(dev_priv); 5508c2ecf20Sopenharmony_ci if (ret) 5518c2ecf20Sopenharmony_ci return ret; 5528c2ecf20Sopenharmony_ci 5538c2ecf20Sopenharmony_ci i915_perf_init(dev_priv); 5548c2ecf20Sopenharmony_ci 5558c2ecf20Sopenharmony_ci ret = i915_ggtt_probe_hw(dev_priv); 5568c2ecf20Sopenharmony_ci if (ret) 5578c2ecf20Sopenharmony_ci goto err_perf; 5588c2ecf20Sopenharmony_ci 5598c2ecf20Sopenharmony_ci ret = drm_fb_helper_remove_conflicting_pci_framebuffers(pdev, "inteldrmfb"); 5608c2ecf20Sopenharmony_ci if (ret) 5618c2ecf20Sopenharmony_ci goto err_ggtt; 5628c2ecf20Sopenharmony_ci 5638c2ecf20Sopenharmony_ci ret = i915_ggtt_init_hw(dev_priv); 5648c2ecf20Sopenharmony_ci if (ret) 5658c2ecf20Sopenharmony_ci goto err_ggtt; 5668c2ecf20Sopenharmony_ci 5678c2ecf20Sopenharmony_ci ret = intel_memory_regions_hw_probe(dev_priv); 5688c2ecf20Sopenharmony_ci if (ret) 5698c2ecf20Sopenharmony_ci goto err_ggtt; 5708c2ecf20Sopenharmony_ci 5718c2ecf20Sopenharmony_ci intel_gt_init_hw_early(&dev_priv->gt, &dev_priv->ggtt); 5728c2ecf20Sopenharmony_ci 5738c2ecf20Sopenharmony_ci ret = i915_ggtt_enable_hw(dev_priv); 5748c2ecf20Sopenharmony_ci if (ret) { 5758c2ecf20Sopenharmony_ci drm_err(&dev_priv->drm, "failed to enable GGTT\n"); 5768c2ecf20Sopenharmony_ci goto err_mem_regions; 5778c2ecf20Sopenharmony_ci } 5788c2ecf20Sopenharmony_ci 5798c2ecf20Sopenharmony_ci pci_set_master(pdev); 5808c2ecf20Sopenharmony_ci 5818c2ecf20Sopenharmony_ci intel_gt_init_workarounds(dev_priv); 5828c2ecf20Sopenharmony_ci 5838c2ecf20Sopenharmony_ci /* On the 945G/GM, the chipset reports the MSI capability on the 5848c2ecf20Sopenharmony_ci * integrated graphics even though the support isn't actually there 5858c2ecf20Sopenharmony_ci * according to the published specs. It doesn't appear to function 5868c2ecf20Sopenharmony_ci * correctly in testing on 945G. 5878c2ecf20Sopenharmony_ci * This may be a side effect of MSI having been made available for PEG 5888c2ecf20Sopenharmony_ci * and the registers being closely associated. 5898c2ecf20Sopenharmony_ci * 5908c2ecf20Sopenharmony_ci * According to chipset errata, on the 965GM, MSI interrupts may 5918c2ecf20Sopenharmony_ci * be lost or delayed, and was defeatured. MSI interrupts seem to 5928c2ecf20Sopenharmony_ci * get lost on g4x as well, and interrupt delivery seems to stay 5938c2ecf20Sopenharmony_ci * properly dead afterwards. So we'll just disable them for all 5948c2ecf20Sopenharmony_ci * pre-gen5 chipsets. 5958c2ecf20Sopenharmony_ci * 5968c2ecf20Sopenharmony_ci * dp aux and gmbus irq on gen4 seems to be able to generate legacy 5978c2ecf20Sopenharmony_ci * interrupts even when in MSI mode. This results in spurious 5988c2ecf20Sopenharmony_ci * interrupt warnings if the legacy irq no. is shared with another 5998c2ecf20Sopenharmony_ci * device. The kernel then disables that interrupt source and so 6008c2ecf20Sopenharmony_ci * prevents the other device from working properly. 6018c2ecf20Sopenharmony_ci */ 6028c2ecf20Sopenharmony_ci if (INTEL_GEN(dev_priv) >= 5) { 6038c2ecf20Sopenharmony_ci if (pci_enable_msi(pdev) < 0) 6048c2ecf20Sopenharmony_ci drm_dbg(&dev_priv->drm, "can't enable MSI"); 6058c2ecf20Sopenharmony_ci } 6068c2ecf20Sopenharmony_ci 6078c2ecf20Sopenharmony_ci ret = intel_gvt_init(dev_priv); 6088c2ecf20Sopenharmony_ci if (ret) 6098c2ecf20Sopenharmony_ci goto err_msi; 6108c2ecf20Sopenharmony_ci 6118c2ecf20Sopenharmony_ci intel_opregion_setup(dev_priv); 6128c2ecf20Sopenharmony_ci 6138c2ecf20Sopenharmony_ci intel_pcode_init(dev_priv); 6148c2ecf20Sopenharmony_ci 6158c2ecf20Sopenharmony_ci /* 6168c2ecf20Sopenharmony_ci * Fill the dram structure to get the system raw bandwidth and 6178c2ecf20Sopenharmony_ci * dram info. This will be used for memory latency calculation. 6188c2ecf20Sopenharmony_ci */ 6198c2ecf20Sopenharmony_ci intel_dram_detect(dev_priv); 6208c2ecf20Sopenharmony_ci 6218c2ecf20Sopenharmony_ci intel_bw_init_hw(dev_priv); 6228c2ecf20Sopenharmony_ci 6238c2ecf20Sopenharmony_ci return 0; 6248c2ecf20Sopenharmony_ci 6258c2ecf20Sopenharmony_cierr_msi: 6268c2ecf20Sopenharmony_ci if (pdev->msi_enabled) 6278c2ecf20Sopenharmony_ci pci_disable_msi(pdev); 6288c2ecf20Sopenharmony_cierr_mem_regions: 6298c2ecf20Sopenharmony_ci intel_memory_regions_driver_release(dev_priv); 6308c2ecf20Sopenharmony_cierr_ggtt: 6318c2ecf20Sopenharmony_ci i915_ggtt_driver_release(dev_priv); 6328c2ecf20Sopenharmony_cierr_perf: 6338c2ecf20Sopenharmony_ci i915_perf_fini(dev_priv); 6348c2ecf20Sopenharmony_ci return ret; 6358c2ecf20Sopenharmony_ci} 6368c2ecf20Sopenharmony_ci 6378c2ecf20Sopenharmony_ci/** 6388c2ecf20Sopenharmony_ci * i915_driver_hw_remove - cleanup the setup done in i915_driver_hw_probe() 6398c2ecf20Sopenharmony_ci * @dev_priv: device private 6408c2ecf20Sopenharmony_ci */ 6418c2ecf20Sopenharmony_cistatic void i915_driver_hw_remove(struct drm_i915_private *dev_priv) 6428c2ecf20Sopenharmony_ci{ 6438c2ecf20Sopenharmony_ci struct pci_dev *pdev = dev_priv->drm.pdev; 6448c2ecf20Sopenharmony_ci 6458c2ecf20Sopenharmony_ci i915_perf_fini(dev_priv); 6468c2ecf20Sopenharmony_ci 6478c2ecf20Sopenharmony_ci if (pdev->msi_enabled) 6488c2ecf20Sopenharmony_ci pci_disable_msi(pdev); 6498c2ecf20Sopenharmony_ci} 6508c2ecf20Sopenharmony_ci 6518c2ecf20Sopenharmony_ci/** 6528c2ecf20Sopenharmony_ci * i915_driver_register - register the driver with the rest of the system 6538c2ecf20Sopenharmony_ci * @dev_priv: device private 6548c2ecf20Sopenharmony_ci * 6558c2ecf20Sopenharmony_ci * Perform any steps necessary to make the driver available via kernel 6568c2ecf20Sopenharmony_ci * internal or userspace interfaces. 6578c2ecf20Sopenharmony_ci */ 6588c2ecf20Sopenharmony_cistatic void i915_driver_register(struct drm_i915_private *dev_priv) 6598c2ecf20Sopenharmony_ci{ 6608c2ecf20Sopenharmony_ci struct drm_device *dev = &dev_priv->drm; 6618c2ecf20Sopenharmony_ci 6628c2ecf20Sopenharmony_ci i915_gem_driver_register(dev_priv); 6638c2ecf20Sopenharmony_ci i915_pmu_register(dev_priv); 6648c2ecf20Sopenharmony_ci 6658c2ecf20Sopenharmony_ci intel_vgpu_register(dev_priv); 6668c2ecf20Sopenharmony_ci 6678c2ecf20Sopenharmony_ci /* Reveal our presence to userspace */ 6688c2ecf20Sopenharmony_ci if (drm_dev_register(dev, 0) == 0) { 6698c2ecf20Sopenharmony_ci i915_debugfs_register(dev_priv); 6708c2ecf20Sopenharmony_ci intel_display_debugfs_register(dev_priv); 6718c2ecf20Sopenharmony_ci i915_setup_sysfs(dev_priv); 6728c2ecf20Sopenharmony_ci 6738c2ecf20Sopenharmony_ci /* Depends on sysfs having been initialized */ 6748c2ecf20Sopenharmony_ci i915_perf_register(dev_priv); 6758c2ecf20Sopenharmony_ci } else 6768c2ecf20Sopenharmony_ci drm_err(&dev_priv->drm, 6778c2ecf20Sopenharmony_ci "Failed to register driver for userspace access!\n"); 6788c2ecf20Sopenharmony_ci 6798c2ecf20Sopenharmony_ci if (HAS_DISPLAY(dev_priv)) { 6808c2ecf20Sopenharmony_ci /* Must be done after probing outputs */ 6818c2ecf20Sopenharmony_ci intel_opregion_register(dev_priv); 6828c2ecf20Sopenharmony_ci acpi_video_register(); 6838c2ecf20Sopenharmony_ci } 6848c2ecf20Sopenharmony_ci 6858c2ecf20Sopenharmony_ci intel_gt_driver_register(&dev_priv->gt); 6868c2ecf20Sopenharmony_ci 6878c2ecf20Sopenharmony_ci intel_audio_init(dev_priv); 6888c2ecf20Sopenharmony_ci 6898c2ecf20Sopenharmony_ci /* 6908c2ecf20Sopenharmony_ci * Some ports require correctly set-up hpd registers for detection to 6918c2ecf20Sopenharmony_ci * work properly (leading to ghost connected connector status), e.g. VGA 6928c2ecf20Sopenharmony_ci * on gm45. Hence we can only set up the initial fbdev config after hpd 6938c2ecf20Sopenharmony_ci * irqs are fully enabled. We do it last so that the async config 6948c2ecf20Sopenharmony_ci * cannot run before the connectors are registered. 6958c2ecf20Sopenharmony_ci */ 6968c2ecf20Sopenharmony_ci intel_fbdev_initial_config_async(dev); 6978c2ecf20Sopenharmony_ci 6988c2ecf20Sopenharmony_ci /* 6998c2ecf20Sopenharmony_ci * We need to coordinate the hotplugs with the asynchronous fbdev 7008c2ecf20Sopenharmony_ci * configuration, for which we use the fbdev->async_cookie. 7018c2ecf20Sopenharmony_ci */ 7028c2ecf20Sopenharmony_ci if (HAS_DISPLAY(dev_priv)) 7038c2ecf20Sopenharmony_ci drm_kms_helper_poll_init(dev); 7048c2ecf20Sopenharmony_ci 7058c2ecf20Sopenharmony_ci intel_power_domains_enable(dev_priv); 7068c2ecf20Sopenharmony_ci intel_runtime_pm_enable(&dev_priv->runtime_pm); 7078c2ecf20Sopenharmony_ci 7088c2ecf20Sopenharmony_ci intel_register_dsm_handler(); 7098c2ecf20Sopenharmony_ci 7108c2ecf20Sopenharmony_ci if (i915_switcheroo_register(dev_priv)) 7118c2ecf20Sopenharmony_ci drm_err(&dev_priv->drm, "Failed to register vga switcheroo!\n"); 7128c2ecf20Sopenharmony_ci} 7138c2ecf20Sopenharmony_ci 7148c2ecf20Sopenharmony_ci/** 7158c2ecf20Sopenharmony_ci * i915_driver_unregister - cleanup the registration done in i915_driver_regiser() 7168c2ecf20Sopenharmony_ci * @dev_priv: device private 7178c2ecf20Sopenharmony_ci */ 7188c2ecf20Sopenharmony_cistatic void i915_driver_unregister(struct drm_i915_private *dev_priv) 7198c2ecf20Sopenharmony_ci{ 7208c2ecf20Sopenharmony_ci i915_switcheroo_unregister(dev_priv); 7218c2ecf20Sopenharmony_ci 7228c2ecf20Sopenharmony_ci intel_unregister_dsm_handler(); 7238c2ecf20Sopenharmony_ci 7248c2ecf20Sopenharmony_ci intel_runtime_pm_disable(&dev_priv->runtime_pm); 7258c2ecf20Sopenharmony_ci intel_power_domains_disable(dev_priv); 7268c2ecf20Sopenharmony_ci 7278c2ecf20Sopenharmony_ci intel_fbdev_unregister(dev_priv); 7288c2ecf20Sopenharmony_ci intel_audio_deinit(dev_priv); 7298c2ecf20Sopenharmony_ci 7308c2ecf20Sopenharmony_ci /* 7318c2ecf20Sopenharmony_ci * After flushing the fbdev (incl. a late async config which will 7328c2ecf20Sopenharmony_ci * have delayed queuing of a hotplug event), then flush the hotplug 7338c2ecf20Sopenharmony_ci * events. 7348c2ecf20Sopenharmony_ci */ 7358c2ecf20Sopenharmony_ci drm_kms_helper_poll_fini(&dev_priv->drm); 7368c2ecf20Sopenharmony_ci 7378c2ecf20Sopenharmony_ci intel_gt_driver_unregister(&dev_priv->gt); 7388c2ecf20Sopenharmony_ci acpi_video_unregister(); 7398c2ecf20Sopenharmony_ci intel_opregion_unregister(dev_priv); 7408c2ecf20Sopenharmony_ci 7418c2ecf20Sopenharmony_ci i915_perf_unregister(dev_priv); 7428c2ecf20Sopenharmony_ci i915_pmu_unregister(dev_priv); 7438c2ecf20Sopenharmony_ci 7448c2ecf20Sopenharmony_ci i915_teardown_sysfs(dev_priv); 7458c2ecf20Sopenharmony_ci drm_dev_unplug(&dev_priv->drm); 7468c2ecf20Sopenharmony_ci 7478c2ecf20Sopenharmony_ci i915_gem_driver_unregister(dev_priv); 7488c2ecf20Sopenharmony_ci} 7498c2ecf20Sopenharmony_ci 7508c2ecf20Sopenharmony_cistatic void i915_welcome_messages(struct drm_i915_private *dev_priv) 7518c2ecf20Sopenharmony_ci{ 7528c2ecf20Sopenharmony_ci if (drm_debug_enabled(DRM_UT_DRIVER)) { 7538c2ecf20Sopenharmony_ci struct drm_printer p = drm_debug_printer("i915 device info:"); 7548c2ecf20Sopenharmony_ci 7558c2ecf20Sopenharmony_ci drm_printf(&p, "pciid=0x%04x rev=0x%02x platform=%s (subplatform=0x%x) gen=%i\n", 7568c2ecf20Sopenharmony_ci INTEL_DEVID(dev_priv), 7578c2ecf20Sopenharmony_ci INTEL_REVID(dev_priv), 7588c2ecf20Sopenharmony_ci intel_platform_name(INTEL_INFO(dev_priv)->platform), 7598c2ecf20Sopenharmony_ci intel_subplatform(RUNTIME_INFO(dev_priv), 7608c2ecf20Sopenharmony_ci INTEL_INFO(dev_priv)->platform), 7618c2ecf20Sopenharmony_ci INTEL_GEN(dev_priv)); 7628c2ecf20Sopenharmony_ci 7638c2ecf20Sopenharmony_ci intel_device_info_print_static(INTEL_INFO(dev_priv), &p); 7648c2ecf20Sopenharmony_ci intel_device_info_print_runtime(RUNTIME_INFO(dev_priv), &p); 7658c2ecf20Sopenharmony_ci intel_gt_info_print(&dev_priv->gt.info, &p); 7668c2ecf20Sopenharmony_ci } 7678c2ecf20Sopenharmony_ci 7688c2ecf20Sopenharmony_ci if (IS_ENABLED(CONFIG_DRM_I915_DEBUG)) 7698c2ecf20Sopenharmony_ci drm_info(&dev_priv->drm, "DRM_I915_DEBUG enabled\n"); 7708c2ecf20Sopenharmony_ci if (IS_ENABLED(CONFIG_DRM_I915_DEBUG_GEM)) 7718c2ecf20Sopenharmony_ci drm_info(&dev_priv->drm, "DRM_I915_DEBUG_GEM enabled\n"); 7728c2ecf20Sopenharmony_ci if (IS_ENABLED(CONFIG_DRM_I915_DEBUG_RUNTIME_PM)) 7738c2ecf20Sopenharmony_ci drm_info(&dev_priv->drm, 7748c2ecf20Sopenharmony_ci "DRM_I915_DEBUG_RUNTIME_PM enabled\n"); 7758c2ecf20Sopenharmony_ci} 7768c2ecf20Sopenharmony_ci 7778c2ecf20Sopenharmony_cistatic struct drm_i915_private * 7788c2ecf20Sopenharmony_cii915_driver_create(struct pci_dev *pdev, const struct pci_device_id *ent) 7798c2ecf20Sopenharmony_ci{ 7808c2ecf20Sopenharmony_ci const struct intel_device_info *match_info = 7818c2ecf20Sopenharmony_ci (struct intel_device_info *)ent->driver_data; 7828c2ecf20Sopenharmony_ci struct intel_device_info *device_info; 7838c2ecf20Sopenharmony_ci struct drm_i915_private *i915; 7848c2ecf20Sopenharmony_ci 7858c2ecf20Sopenharmony_ci i915 = devm_drm_dev_alloc(&pdev->dev, &driver, 7868c2ecf20Sopenharmony_ci struct drm_i915_private, drm); 7878c2ecf20Sopenharmony_ci if (IS_ERR(i915)) 7888c2ecf20Sopenharmony_ci return i915; 7898c2ecf20Sopenharmony_ci 7908c2ecf20Sopenharmony_ci i915->drm.pdev = pdev; 7918c2ecf20Sopenharmony_ci pci_set_drvdata(pdev, i915); 7928c2ecf20Sopenharmony_ci 7938c2ecf20Sopenharmony_ci /* Device parameters start as a copy of module parameters. */ 7948c2ecf20Sopenharmony_ci i915_params_copy(&i915->params, &i915_modparams); 7958c2ecf20Sopenharmony_ci 7968c2ecf20Sopenharmony_ci /* Setup the write-once "constant" device info */ 7978c2ecf20Sopenharmony_ci device_info = mkwrite_device_info(i915); 7988c2ecf20Sopenharmony_ci memcpy(device_info, match_info, sizeof(*device_info)); 7998c2ecf20Sopenharmony_ci RUNTIME_INFO(i915)->device_id = pdev->device; 8008c2ecf20Sopenharmony_ci 8018c2ecf20Sopenharmony_ci BUG_ON(device_info->gen > BITS_PER_TYPE(device_info->gen_mask)); 8028c2ecf20Sopenharmony_ci 8038c2ecf20Sopenharmony_ci return i915; 8048c2ecf20Sopenharmony_ci} 8058c2ecf20Sopenharmony_ci 8068c2ecf20Sopenharmony_ci/** 8078c2ecf20Sopenharmony_ci * i915_driver_probe - setup chip and create an initial config 8088c2ecf20Sopenharmony_ci * @pdev: PCI device 8098c2ecf20Sopenharmony_ci * @ent: matching PCI ID entry 8108c2ecf20Sopenharmony_ci * 8118c2ecf20Sopenharmony_ci * The driver probe routine has to do several things: 8128c2ecf20Sopenharmony_ci * - drive output discovery via intel_modeset_init() 8138c2ecf20Sopenharmony_ci * - initialize the memory manager 8148c2ecf20Sopenharmony_ci * - allocate initial config memory 8158c2ecf20Sopenharmony_ci * - setup the DRM framebuffer with the allocated memory 8168c2ecf20Sopenharmony_ci */ 8178c2ecf20Sopenharmony_ciint i915_driver_probe(struct pci_dev *pdev, const struct pci_device_id *ent) 8188c2ecf20Sopenharmony_ci{ 8198c2ecf20Sopenharmony_ci const struct intel_device_info *match_info = 8208c2ecf20Sopenharmony_ci (struct intel_device_info *)ent->driver_data; 8218c2ecf20Sopenharmony_ci struct drm_i915_private *i915; 8228c2ecf20Sopenharmony_ci int ret; 8238c2ecf20Sopenharmony_ci 8248c2ecf20Sopenharmony_ci i915 = i915_driver_create(pdev, ent); 8258c2ecf20Sopenharmony_ci if (IS_ERR(i915)) 8268c2ecf20Sopenharmony_ci return PTR_ERR(i915); 8278c2ecf20Sopenharmony_ci 8288c2ecf20Sopenharmony_ci /* Disable nuclear pageflip by default on pre-ILK */ 8298c2ecf20Sopenharmony_ci if (!i915->params.nuclear_pageflip && match_info->gen < 5) 8308c2ecf20Sopenharmony_ci i915->drm.driver_features &= ~DRIVER_ATOMIC; 8318c2ecf20Sopenharmony_ci 8328c2ecf20Sopenharmony_ci /* 8338c2ecf20Sopenharmony_ci * Check if we support fake LMEM -- for now we only unleash this for 8348c2ecf20Sopenharmony_ci * the live selftests(test-and-exit). 8358c2ecf20Sopenharmony_ci */ 8368c2ecf20Sopenharmony_ci#if IS_ENABLED(CONFIG_DRM_I915_SELFTEST) 8378c2ecf20Sopenharmony_ci if (IS_ENABLED(CONFIG_DRM_I915_UNSTABLE_FAKE_LMEM)) { 8388c2ecf20Sopenharmony_ci if (INTEL_GEN(i915) >= 9 && i915_selftest.live < 0 && 8398c2ecf20Sopenharmony_ci i915->params.fake_lmem_start) { 8408c2ecf20Sopenharmony_ci mkwrite_device_info(i915)->memory_regions = 8418c2ecf20Sopenharmony_ci REGION_SMEM | REGION_LMEM | REGION_STOLEN; 8428c2ecf20Sopenharmony_ci mkwrite_device_info(i915)->is_dgfx = true; 8438c2ecf20Sopenharmony_ci GEM_BUG_ON(!HAS_LMEM(i915)); 8448c2ecf20Sopenharmony_ci GEM_BUG_ON(!IS_DGFX(i915)); 8458c2ecf20Sopenharmony_ci } 8468c2ecf20Sopenharmony_ci } 8478c2ecf20Sopenharmony_ci#endif 8488c2ecf20Sopenharmony_ci 8498c2ecf20Sopenharmony_ci ret = pci_enable_device(pdev); 8508c2ecf20Sopenharmony_ci if (ret) 8518c2ecf20Sopenharmony_ci goto out_fini; 8528c2ecf20Sopenharmony_ci 8538c2ecf20Sopenharmony_ci ret = i915_driver_early_probe(i915); 8548c2ecf20Sopenharmony_ci if (ret < 0) 8558c2ecf20Sopenharmony_ci goto out_pci_disable; 8568c2ecf20Sopenharmony_ci 8578c2ecf20Sopenharmony_ci disable_rpm_wakeref_asserts(&i915->runtime_pm); 8588c2ecf20Sopenharmony_ci 8598c2ecf20Sopenharmony_ci intel_vgpu_detect(i915); 8608c2ecf20Sopenharmony_ci 8618c2ecf20Sopenharmony_ci ret = i915_driver_mmio_probe(i915); 8628c2ecf20Sopenharmony_ci if (ret < 0) 8638c2ecf20Sopenharmony_ci goto out_runtime_pm_put; 8648c2ecf20Sopenharmony_ci 8658c2ecf20Sopenharmony_ci ret = i915_driver_hw_probe(i915); 8668c2ecf20Sopenharmony_ci if (ret < 0) 8678c2ecf20Sopenharmony_ci goto out_cleanup_mmio; 8688c2ecf20Sopenharmony_ci 8698c2ecf20Sopenharmony_ci ret = intel_modeset_init_noirq(i915); 8708c2ecf20Sopenharmony_ci if (ret < 0) 8718c2ecf20Sopenharmony_ci goto out_cleanup_hw; 8728c2ecf20Sopenharmony_ci 8738c2ecf20Sopenharmony_ci ret = intel_irq_install(i915); 8748c2ecf20Sopenharmony_ci if (ret) 8758c2ecf20Sopenharmony_ci goto out_cleanup_modeset; 8768c2ecf20Sopenharmony_ci 8778c2ecf20Sopenharmony_ci ret = intel_modeset_init_nogem(i915); 8788c2ecf20Sopenharmony_ci if (ret) 8798c2ecf20Sopenharmony_ci goto out_cleanup_irq; 8808c2ecf20Sopenharmony_ci 8818c2ecf20Sopenharmony_ci ret = i915_gem_init(i915); 8828c2ecf20Sopenharmony_ci if (ret) 8838c2ecf20Sopenharmony_ci goto out_cleanup_modeset2; 8848c2ecf20Sopenharmony_ci 8858c2ecf20Sopenharmony_ci ret = intel_modeset_init(i915); 8868c2ecf20Sopenharmony_ci if (ret) 8878c2ecf20Sopenharmony_ci goto out_cleanup_gem; 8888c2ecf20Sopenharmony_ci 8898c2ecf20Sopenharmony_ci i915_driver_register(i915); 8908c2ecf20Sopenharmony_ci 8918c2ecf20Sopenharmony_ci enable_rpm_wakeref_asserts(&i915->runtime_pm); 8928c2ecf20Sopenharmony_ci 8938c2ecf20Sopenharmony_ci i915_welcome_messages(i915); 8948c2ecf20Sopenharmony_ci 8958c2ecf20Sopenharmony_ci i915->do_release = true; 8968c2ecf20Sopenharmony_ci 8978c2ecf20Sopenharmony_ci return 0; 8988c2ecf20Sopenharmony_ci 8998c2ecf20Sopenharmony_ciout_cleanup_gem: 9008c2ecf20Sopenharmony_ci i915_gem_suspend(i915); 9018c2ecf20Sopenharmony_ci i915_gem_driver_remove(i915); 9028c2ecf20Sopenharmony_ci i915_gem_driver_release(i915); 9038c2ecf20Sopenharmony_ciout_cleanup_modeset2: 9048c2ecf20Sopenharmony_ci /* FIXME clean up the error path */ 9058c2ecf20Sopenharmony_ci intel_modeset_driver_remove(i915); 9068c2ecf20Sopenharmony_ci intel_irq_uninstall(i915); 9078c2ecf20Sopenharmony_ci intel_modeset_driver_remove_noirq(i915); 9088c2ecf20Sopenharmony_ci goto out_cleanup_modeset; 9098c2ecf20Sopenharmony_ciout_cleanup_irq: 9108c2ecf20Sopenharmony_ci intel_irq_uninstall(i915); 9118c2ecf20Sopenharmony_ciout_cleanup_modeset: 9128c2ecf20Sopenharmony_ci intel_modeset_driver_remove_nogem(i915); 9138c2ecf20Sopenharmony_ciout_cleanup_hw: 9148c2ecf20Sopenharmony_ci i915_driver_hw_remove(i915); 9158c2ecf20Sopenharmony_ci intel_memory_regions_driver_release(i915); 9168c2ecf20Sopenharmony_ci i915_ggtt_driver_release(i915); 9178c2ecf20Sopenharmony_ciout_cleanup_mmio: 9188c2ecf20Sopenharmony_ci i915_driver_mmio_release(i915); 9198c2ecf20Sopenharmony_ciout_runtime_pm_put: 9208c2ecf20Sopenharmony_ci enable_rpm_wakeref_asserts(&i915->runtime_pm); 9218c2ecf20Sopenharmony_ci i915_driver_late_release(i915); 9228c2ecf20Sopenharmony_ciout_pci_disable: 9238c2ecf20Sopenharmony_ci pci_disable_device(pdev); 9248c2ecf20Sopenharmony_ciout_fini: 9258c2ecf20Sopenharmony_ci i915_probe_error(i915, "Device initialization failed (%d)\n", ret); 9268c2ecf20Sopenharmony_ci return ret; 9278c2ecf20Sopenharmony_ci} 9288c2ecf20Sopenharmony_ci 9298c2ecf20Sopenharmony_civoid i915_driver_remove(struct drm_i915_private *i915) 9308c2ecf20Sopenharmony_ci{ 9318c2ecf20Sopenharmony_ci disable_rpm_wakeref_asserts(&i915->runtime_pm); 9328c2ecf20Sopenharmony_ci 9338c2ecf20Sopenharmony_ci i915_driver_unregister(i915); 9348c2ecf20Sopenharmony_ci 9358c2ecf20Sopenharmony_ci /* Flush any external code that still may be under the RCU lock */ 9368c2ecf20Sopenharmony_ci synchronize_rcu(); 9378c2ecf20Sopenharmony_ci 9388c2ecf20Sopenharmony_ci i915_gem_suspend(i915); 9398c2ecf20Sopenharmony_ci 9408c2ecf20Sopenharmony_ci drm_atomic_helper_shutdown(&i915->drm); 9418c2ecf20Sopenharmony_ci 9428c2ecf20Sopenharmony_ci intel_gvt_driver_remove(i915); 9438c2ecf20Sopenharmony_ci 9448c2ecf20Sopenharmony_ci intel_modeset_driver_remove(i915); 9458c2ecf20Sopenharmony_ci 9468c2ecf20Sopenharmony_ci intel_irq_uninstall(i915); 9478c2ecf20Sopenharmony_ci 9488c2ecf20Sopenharmony_ci intel_modeset_driver_remove_noirq(i915); 9498c2ecf20Sopenharmony_ci 9508c2ecf20Sopenharmony_ci i915_reset_error_state(i915); 9518c2ecf20Sopenharmony_ci i915_gem_driver_remove(i915); 9528c2ecf20Sopenharmony_ci 9538c2ecf20Sopenharmony_ci intel_modeset_driver_remove_nogem(i915); 9548c2ecf20Sopenharmony_ci 9558c2ecf20Sopenharmony_ci i915_driver_hw_remove(i915); 9568c2ecf20Sopenharmony_ci 9578c2ecf20Sopenharmony_ci enable_rpm_wakeref_asserts(&i915->runtime_pm); 9588c2ecf20Sopenharmony_ci} 9598c2ecf20Sopenharmony_ci 9608c2ecf20Sopenharmony_cistatic void i915_driver_release(struct drm_device *dev) 9618c2ecf20Sopenharmony_ci{ 9628c2ecf20Sopenharmony_ci struct drm_i915_private *dev_priv = to_i915(dev); 9638c2ecf20Sopenharmony_ci struct intel_runtime_pm *rpm = &dev_priv->runtime_pm; 9648c2ecf20Sopenharmony_ci 9658c2ecf20Sopenharmony_ci if (!dev_priv->do_release) 9668c2ecf20Sopenharmony_ci return; 9678c2ecf20Sopenharmony_ci 9688c2ecf20Sopenharmony_ci disable_rpm_wakeref_asserts(rpm); 9698c2ecf20Sopenharmony_ci 9708c2ecf20Sopenharmony_ci i915_gem_driver_release(dev_priv); 9718c2ecf20Sopenharmony_ci 9728c2ecf20Sopenharmony_ci intel_memory_regions_driver_release(dev_priv); 9738c2ecf20Sopenharmony_ci i915_ggtt_driver_release(dev_priv); 9748c2ecf20Sopenharmony_ci i915_gem_drain_freed_objects(dev_priv); 9758c2ecf20Sopenharmony_ci 9768c2ecf20Sopenharmony_ci i915_driver_mmio_release(dev_priv); 9778c2ecf20Sopenharmony_ci 9788c2ecf20Sopenharmony_ci enable_rpm_wakeref_asserts(rpm); 9798c2ecf20Sopenharmony_ci intel_runtime_pm_driver_release(rpm); 9808c2ecf20Sopenharmony_ci 9818c2ecf20Sopenharmony_ci i915_driver_late_release(dev_priv); 9828c2ecf20Sopenharmony_ci} 9838c2ecf20Sopenharmony_ci 9848c2ecf20Sopenharmony_cistatic int i915_driver_open(struct drm_device *dev, struct drm_file *file) 9858c2ecf20Sopenharmony_ci{ 9868c2ecf20Sopenharmony_ci struct drm_i915_private *i915 = to_i915(dev); 9878c2ecf20Sopenharmony_ci int ret; 9888c2ecf20Sopenharmony_ci 9898c2ecf20Sopenharmony_ci ret = i915_gem_open(i915, file); 9908c2ecf20Sopenharmony_ci if (ret) 9918c2ecf20Sopenharmony_ci return ret; 9928c2ecf20Sopenharmony_ci 9938c2ecf20Sopenharmony_ci return 0; 9948c2ecf20Sopenharmony_ci} 9958c2ecf20Sopenharmony_ci 9968c2ecf20Sopenharmony_ci/** 9978c2ecf20Sopenharmony_ci * i915_driver_lastclose - clean up after all DRM clients have exited 9988c2ecf20Sopenharmony_ci * @dev: DRM device 9998c2ecf20Sopenharmony_ci * 10008c2ecf20Sopenharmony_ci * Take care of cleaning up after all DRM clients have exited. In the 10018c2ecf20Sopenharmony_ci * mode setting case, we want to restore the kernel's initial mode (just 10028c2ecf20Sopenharmony_ci * in case the last client left us in a bad state). 10038c2ecf20Sopenharmony_ci * 10048c2ecf20Sopenharmony_ci * Additionally, in the non-mode setting case, we'll tear down the GTT 10058c2ecf20Sopenharmony_ci * and DMA structures, since the kernel won't be using them, and clea 10068c2ecf20Sopenharmony_ci * up any GEM state. 10078c2ecf20Sopenharmony_ci */ 10088c2ecf20Sopenharmony_cistatic void i915_driver_lastclose(struct drm_device *dev) 10098c2ecf20Sopenharmony_ci{ 10108c2ecf20Sopenharmony_ci intel_fbdev_restore_mode(dev); 10118c2ecf20Sopenharmony_ci vga_switcheroo_process_delayed_switch(); 10128c2ecf20Sopenharmony_ci} 10138c2ecf20Sopenharmony_ci 10148c2ecf20Sopenharmony_cistatic void i915_driver_postclose(struct drm_device *dev, struct drm_file *file) 10158c2ecf20Sopenharmony_ci{ 10168c2ecf20Sopenharmony_ci struct drm_i915_file_private *file_priv = file->driver_priv; 10178c2ecf20Sopenharmony_ci 10188c2ecf20Sopenharmony_ci i915_gem_context_close(file); 10198c2ecf20Sopenharmony_ci 10208c2ecf20Sopenharmony_ci kfree_rcu(file_priv, rcu); 10218c2ecf20Sopenharmony_ci 10228c2ecf20Sopenharmony_ci /* Catch up with all the deferred frees from "this" client */ 10238c2ecf20Sopenharmony_ci i915_gem_flush_free_objects(to_i915(dev)); 10248c2ecf20Sopenharmony_ci} 10258c2ecf20Sopenharmony_ci 10268c2ecf20Sopenharmony_cistatic void intel_suspend_encoders(struct drm_i915_private *dev_priv) 10278c2ecf20Sopenharmony_ci{ 10288c2ecf20Sopenharmony_ci struct drm_device *dev = &dev_priv->drm; 10298c2ecf20Sopenharmony_ci struct intel_encoder *encoder; 10308c2ecf20Sopenharmony_ci 10318c2ecf20Sopenharmony_ci drm_modeset_lock_all(dev); 10328c2ecf20Sopenharmony_ci for_each_intel_encoder(dev, encoder) 10338c2ecf20Sopenharmony_ci if (encoder->suspend) 10348c2ecf20Sopenharmony_ci encoder->suspend(encoder); 10358c2ecf20Sopenharmony_ci drm_modeset_unlock_all(dev); 10368c2ecf20Sopenharmony_ci} 10378c2ecf20Sopenharmony_ci 10388c2ecf20Sopenharmony_cistatic bool suspend_to_idle(struct drm_i915_private *dev_priv) 10398c2ecf20Sopenharmony_ci{ 10408c2ecf20Sopenharmony_ci#if IS_ENABLED(CONFIG_ACPI_SLEEP) 10418c2ecf20Sopenharmony_ci if (acpi_target_system_state() < ACPI_STATE_S3) 10428c2ecf20Sopenharmony_ci return true; 10438c2ecf20Sopenharmony_ci#endif 10448c2ecf20Sopenharmony_ci return false; 10458c2ecf20Sopenharmony_ci} 10468c2ecf20Sopenharmony_ci 10478c2ecf20Sopenharmony_cistatic int i915_drm_prepare(struct drm_device *dev) 10488c2ecf20Sopenharmony_ci{ 10498c2ecf20Sopenharmony_ci struct drm_i915_private *i915 = to_i915(dev); 10508c2ecf20Sopenharmony_ci 10518c2ecf20Sopenharmony_ci /* 10528c2ecf20Sopenharmony_ci * NB intel_display_suspend() may issue new requests after we've 10538c2ecf20Sopenharmony_ci * ostensibly marked the GPU as ready-to-sleep here. We need to 10548c2ecf20Sopenharmony_ci * split out that work and pull it forward so that after point, 10558c2ecf20Sopenharmony_ci * the GPU is not woken again. 10568c2ecf20Sopenharmony_ci */ 10578c2ecf20Sopenharmony_ci i915_gem_suspend(i915); 10588c2ecf20Sopenharmony_ci 10598c2ecf20Sopenharmony_ci return 0; 10608c2ecf20Sopenharmony_ci} 10618c2ecf20Sopenharmony_ci 10628c2ecf20Sopenharmony_cistatic int i915_drm_suspend(struct drm_device *dev) 10638c2ecf20Sopenharmony_ci{ 10648c2ecf20Sopenharmony_ci struct drm_i915_private *dev_priv = to_i915(dev); 10658c2ecf20Sopenharmony_ci struct pci_dev *pdev = dev_priv->drm.pdev; 10668c2ecf20Sopenharmony_ci pci_power_t opregion_target_state; 10678c2ecf20Sopenharmony_ci 10688c2ecf20Sopenharmony_ci disable_rpm_wakeref_asserts(&dev_priv->runtime_pm); 10698c2ecf20Sopenharmony_ci 10708c2ecf20Sopenharmony_ci /* We do a lot of poking in a lot of registers, make sure they work 10718c2ecf20Sopenharmony_ci * properly. */ 10728c2ecf20Sopenharmony_ci intel_power_domains_disable(dev_priv); 10738c2ecf20Sopenharmony_ci 10748c2ecf20Sopenharmony_ci drm_kms_helper_poll_disable(dev); 10758c2ecf20Sopenharmony_ci 10768c2ecf20Sopenharmony_ci pci_save_state(pdev); 10778c2ecf20Sopenharmony_ci 10788c2ecf20Sopenharmony_ci intel_display_suspend(dev); 10798c2ecf20Sopenharmony_ci 10808c2ecf20Sopenharmony_ci intel_dp_mst_suspend(dev_priv); 10818c2ecf20Sopenharmony_ci 10828c2ecf20Sopenharmony_ci intel_runtime_pm_disable_interrupts(dev_priv); 10838c2ecf20Sopenharmony_ci intel_hpd_cancel_work(dev_priv); 10848c2ecf20Sopenharmony_ci 10858c2ecf20Sopenharmony_ci intel_suspend_encoders(dev_priv); 10868c2ecf20Sopenharmony_ci 10878c2ecf20Sopenharmony_ci intel_suspend_hw(dev_priv); 10888c2ecf20Sopenharmony_ci 10898c2ecf20Sopenharmony_ci i915_ggtt_suspend(&dev_priv->ggtt); 10908c2ecf20Sopenharmony_ci 10918c2ecf20Sopenharmony_ci i915_save_state(dev_priv); 10928c2ecf20Sopenharmony_ci 10938c2ecf20Sopenharmony_ci opregion_target_state = suspend_to_idle(dev_priv) ? PCI_D1 : PCI_D3cold; 10948c2ecf20Sopenharmony_ci intel_opregion_suspend(dev_priv, opregion_target_state); 10958c2ecf20Sopenharmony_ci 10968c2ecf20Sopenharmony_ci intel_fbdev_set_suspend(dev, FBINFO_STATE_SUSPENDED, true); 10978c2ecf20Sopenharmony_ci 10988c2ecf20Sopenharmony_ci dev_priv->suspend_count++; 10998c2ecf20Sopenharmony_ci 11008c2ecf20Sopenharmony_ci intel_csr_ucode_suspend(dev_priv); 11018c2ecf20Sopenharmony_ci 11028c2ecf20Sopenharmony_ci enable_rpm_wakeref_asserts(&dev_priv->runtime_pm); 11038c2ecf20Sopenharmony_ci 11048c2ecf20Sopenharmony_ci return 0; 11058c2ecf20Sopenharmony_ci} 11068c2ecf20Sopenharmony_ci 11078c2ecf20Sopenharmony_cistatic enum i915_drm_suspend_mode 11088c2ecf20Sopenharmony_ciget_suspend_mode(struct drm_i915_private *dev_priv, bool hibernate) 11098c2ecf20Sopenharmony_ci{ 11108c2ecf20Sopenharmony_ci if (hibernate) 11118c2ecf20Sopenharmony_ci return I915_DRM_SUSPEND_HIBERNATE; 11128c2ecf20Sopenharmony_ci 11138c2ecf20Sopenharmony_ci if (suspend_to_idle(dev_priv)) 11148c2ecf20Sopenharmony_ci return I915_DRM_SUSPEND_IDLE; 11158c2ecf20Sopenharmony_ci 11168c2ecf20Sopenharmony_ci return I915_DRM_SUSPEND_MEM; 11178c2ecf20Sopenharmony_ci} 11188c2ecf20Sopenharmony_ci 11198c2ecf20Sopenharmony_cistatic int i915_drm_suspend_late(struct drm_device *dev, bool hibernation) 11208c2ecf20Sopenharmony_ci{ 11218c2ecf20Sopenharmony_ci struct drm_i915_private *dev_priv = to_i915(dev); 11228c2ecf20Sopenharmony_ci struct pci_dev *pdev = dev_priv->drm.pdev; 11238c2ecf20Sopenharmony_ci struct intel_runtime_pm *rpm = &dev_priv->runtime_pm; 11248c2ecf20Sopenharmony_ci int ret; 11258c2ecf20Sopenharmony_ci 11268c2ecf20Sopenharmony_ci disable_rpm_wakeref_asserts(rpm); 11278c2ecf20Sopenharmony_ci 11288c2ecf20Sopenharmony_ci i915_gem_suspend_late(dev_priv); 11298c2ecf20Sopenharmony_ci 11308c2ecf20Sopenharmony_ci intel_uncore_suspend(&dev_priv->uncore); 11318c2ecf20Sopenharmony_ci 11328c2ecf20Sopenharmony_ci intel_power_domains_suspend(dev_priv, 11338c2ecf20Sopenharmony_ci get_suspend_mode(dev_priv, hibernation)); 11348c2ecf20Sopenharmony_ci 11358c2ecf20Sopenharmony_ci intel_display_power_suspend_late(dev_priv); 11368c2ecf20Sopenharmony_ci 11378c2ecf20Sopenharmony_ci ret = vlv_suspend_complete(dev_priv); 11388c2ecf20Sopenharmony_ci if (ret) { 11398c2ecf20Sopenharmony_ci drm_err(&dev_priv->drm, "Suspend complete failed: %d\n", ret); 11408c2ecf20Sopenharmony_ci intel_power_domains_resume(dev_priv); 11418c2ecf20Sopenharmony_ci 11428c2ecf20Sopenharmony_ci goto out; 11438c2ecf20Sopenharmony_ci } 11448c2ecf20Sopenharmony_ci 11458c2ecf20Sopenharmony_ci pci_disable_device(pdev); 11468c2ecf20Sopenharmony_ci /* 11478c2ecf20Sopenharmony_ci * During hibernation on some platforms the BIOS may try to access 11488c2ecf20Sopenharmony_ci * the device even though it's already in D3 and hang the machine. So 11498c2ecf20Sopenharmony_ci * leave the device in D0 on those platforms and hope the BIOS will 11508c2ecf20Sopenharmony_ci * power down the device properly. The issue was seen on multiple old 11518c2ecf20Sopenharmony_ci * GENs with different BIOS vendors, so having an explicit blacklist 11528c2ecf20Sopenharmony_ci * is inpractical; apply the workaround on everything pre GEN6. The 11538c2ecf20Sopenharmony_ci * platforms where the issue was seen: 11548c2ecf20Sopenharmony_ci * Lenovo Thinkpad X301, X61s, X60, T60, X41 11558c2ecf20Sopenharmony_ci * Fujitsu FSC S7110 11568c2ecf20Sopenharmony_ci * Acer Aspire 1830T 11578c2ecf20Sopenharmony_ci */ 11588c2ecf20Sopenharmony_ci if (!(hibernation && INTEL_GEN(dev_priv) < 6)) 11598c2ecf20Sopenharmony_ci pci_set_power_state(pdev, PCI_D3hot); 11608c2ecf20Sopenharmony_ci 11618c2ecf20Sopenharmony_ciout: 11628c2ecf20Sopenharmony_ci enable_rpm_wakeref_asserts(rpm); 11638c2ecf20Sopenharmony_ci if (!dev_priv->uncore.user_forcewake_count) 11648c2ecf20Sopenharmony_ci intel_runtime_pm_driver_release(rpm); 11658c2ecf20Sopenharmony_ci 11668c2ecf20Sopenharmony_ci return ret; 11678c2ecf20Sopenharmony_ci} 11688c2ecf20Sopenharmony_ci 11698c2ecf20Sopenharmony_ciint i915_suspend_switcheroo(struct drm_i915_private *i915, pm_message_t state) 11708c2ecf20Sopenharmony_ci{ 11718c2ecf20Sopenharmony_ci int error; 11728c2ecf20Sopenharmony_ci 11738c2ecf20Sopenharmony_ci if (drm_WARN_ON_ONCE(&i915->drm, state.event != PM_EVENT_SUSPEND && 11748c2ecf20Sopenharmony_ci state.event != PM_EVENT_FREEZE)) 11758c2ecf20Sopenharmony_ci return -EINVAL; 11768c2ecf20Sopenharmony_ci 11778c2ecf20Sopenharmony_ci if (i915->drm.switch_power_state == DRM_SWITCH_POWER_OFF) 11788c2ecf20Sopenharmony_ci return 0; 11798c2ecf20Sopenharmony_ci 11808c2ecf20Sopenharmony_ci error = i915_drm_suspend(&i915->drm); 11818c2ecf20Sopenharmony_ci if (error) 11828c2ecf20Sopenharmony_ci return error; 11838c2ecf20Sopenharmony_ci 11848c2ecf20Sopenharmony_ci return i915_drm_suspend_late(&i915->drm, false); 11858c2ecf20Sopenharmony_ci} 11868c2ecf20Sopenharmony_ci 11878c2ecf20Sopenharmony_cistatic int i915_drm_resume(struct drm_device *dev) 11888c2ecf20Sopenharmony_ci{ 11898c2ecf20Sopenharmony_ci struct drm_i915_private *dev_priv = to_i915(dev); 11908c2ecf20Sopenharmony_ci int ret; 11918c2ecf20Sopenharmony_ci 11928c2ecf20Sopenharmony_ci disable_rpm_wakeref_asserts(&dev_priv->runtime_pm); 11938c2ecf20Sopenharmony_ci 11948c2ecf20Sopenharmony_ci sanitize_gpu(dev_priv); 11958c2ecf20Sopenharmony_ci 11968c2ecf20Sopenharmony_ci ret = i915_ggtt_enable_hw(dev_priv); 11978c2ecf20Sopenharmony_ci if (ret) 11988c2ecf20Sopenharmony_ci drm_err(&dev_priv->drm, "failed to re-enable GGTT\n"); 11998c2ecf20Sopenharmony_ci 12008c2ecf20Sopenharmony_ci i915_ggtt_resume(&dev_priv->ggtt); 12018c2ecf20Sopenharmony_ci 12028c2ecf20Sopenharmony_ci intel_csr_ucode_resume(dev_priv); 12038c2ecf20Sopenharmony_ci 12048c2ecf20Sopenharmony_ci i915_restore_state(dev_priv); 12058c2ecf20Sopenharmony_ci intel_pps_unlock_regs_wa(dev_priv); 12068c2ecf20Sopenharmony_ci 12078c2ecf20Sopenharmony_ci intel_init_pch_refclk(dev_priv); 12088c2ecf20Sopenharmony_ci 12098c2ecf20Sopenharmony_ci /* 12108c2ecf20Sopenharmony_ci * Interrupts have to be enabled before any batches are run. If not the 12118c2ecf20Sopenharmony_ci * GPU will hang. i915_gem_init_hw() will initiate batches to 12128c2ecf20Sopenharmony_ci * update/restore the context. 12138c2ecf20Sopenharmony_ci * 12148c2ecf20Sopenharmony_ci * drm_mode_config_reset() needs AUX interrupts. 12158c2ecf20Sopenharmony_ci * 12168c2ecf20Sopenharmony_ci * Modeset enabling in intel_modeset_init_hw() also needs working 12178c2ecf20Sopenharmony_ci * interrupts. 12188c2ecf20Sopenharmony_ci */ 12198c2ecf20Sopenharmony_ci intel_runtime_pm_enable_interrupts(dev_priv); 12208c2ecf20Sopenharmony_ci 12218c2ecf20Sopenharmony_ci drm_mode_config_reset(dev); 12228c2ecf20Sopenharmony_ci 12238c2ecf20Sopenharmony_ci i915_gem_resume(dev_priv); 12248c2ecf20Sopenharmony_ci 12258c2ecf20Sopenharmony_ci intel_modeset_init_hw(dev_priv); 12268c2ecf20Sopenharmony_ci intel_init_clock_gating(dev_priv); 12278c2ecf20Sopenharmony_ci 12288c2ecf20Sopenharmony_ci spin_lock_irq(&dev_priv->irq_lock); 12298c2ecf20Sopenharmony_ci if (dev_priv->display.hpd_irq_setup) 12308c2ecf20Sopenharmony_ci dev_priv->display.hpd_irq_setup(dev_priv); 12318c2ecf20Sopenharmony_ci spin_unlock_irq(&dev_priv->irq_lock); 12328c2ecf20Sopenharmony_ci 12338c2ecf20Sopenharmony_ci intel_dp_mst_resume(dev_priv); 12348c2ecf20Sopenharmony_ci 12358c2ecf20Sopenharmony_ci intel_display_resume(dev); 12368c2ecf20Sopenharmony_ci 12378c2ecf20Sopenharmony_ci drm_kms_helper_poll_enable(dev); 12388c2ecf20Sopenharmony_ci 12398c2ecf20Sopenharmony_ci /* 12408c2ecf20Sopenharmony_ci * ... but also need to make sure that hotplug processing 12418c2ecf20Sopenharmony_ci * doesn't cause havoc. Like in the driver load code we don't 12428c2ecf20Sopenharmony_ci * bother with the tiny race here where we might lose hotplug 12438c2ecf20Sopenharmony_ci * notifications. 12448c2ecf20Sopenharmony_ci * */ 12458c2ecf20Sopenharmony_ci intel_hpd_init(dev_priv); 12468c2ecf20Sopenharmony_ci 12478c2ecf20Sopenharmony_ci intel_opregion_resume(dev_priv); 12488c2ecf20Sopenharmony_ci 12498c2ecf20Sopenharmony_ci intel_fbdev_set_suspend(dev, FBINFO_STATE_RUNNING, false); 12508c2ecf20Sopenharmony_ci 12518c2ecf20Sopenharmony_ci intel_power_domains_enable(dev_priv); 12528c2ecf20Sopenharmony_ci 12538c2ecf20Sopenharmony_ci enable_rpm_wakeref_asserts(&dev_priv->runtime_pm); 12548c2ecf20Sopenharmony_ci 12558c2ecf20Sopenharmony_ci return 0; 12568c2ecf20Sopenharmony_ci} 12578c2ecf20Sopenharmony_ci 12588c2ecf20Sopenharmony_cistatic int i915_drm_resume_early(struct drm_device *dev) 12598c2ecf20Sopenharmony_ci{ 12608c2ecf20Sopenharmony_ci struct drm_i915_private *dev_priv = to_i915(dev); 12618c2ecf20Sopenharmony_ci struct pci_dev *pdev = dev_priv->drm.pdev; 12628c2ecf20Sopenharmony_ci int ret; 12638c2ecf20Sopenharmony_ci 12648c2ecf20Sopenharmony_ci /* 12658c2ecf20Sopenharmony_ci * We have a resume ordering issue with the snd-hda driver also 12668c2ecf20Sopenharmony_ci * requiring our device to be power up. Due to the lack of a 12678c2ecf20Sopenharmony_ci * parent/child relationship we currently solve this with an early 12688c2ecf20Sopenharmony_ci * resume hook. 12698c2ecf20Sopenharmony_ci * 12708c2ecf20Sopenharmony_ci * FIXME: This should be solved with a special hdmi sink device or 12718c2ecf20Sopenharmony_ci * similar so that power domains can be employed. 12728c2ecf20Sopenharmony_ci */ 12738c2ecf20Sopenharmony_ci 12748c2ecf20Sopenharmony_ci /* 12758c2ecf20Sopenharmony_ci * Note that we need to set the power state explicitly, since we 12768c2ecf20Sopenharmony_ci * powered off the device during freeze and the PCI core won't power 12778c2ecf20Sopenharmony_ci * it back up for us during thaw. Powering off the device during 12788c2ecf20Sopenharmony_ci * freeze is not a hard requirement though, and during the 12798c2ecf20Sopenharmony_ci * suspend/resume phases the PCI core makes sure we get here with the 12808c2ecf20Sopenharmony_ci * device powered on. So in case we change our freeze logic and keep 12818c2ecf20Sopenharmony_ci * the device powered we can also remove the following set power state 12828c2ecf20Sopenharmony_ci * call. 12838c2ecf20Sopenharmony_ci */ 12848c2ecf20Sopenharmony_ci ret = pci_set_power_state(pdev, PCI_D0); 12858c2ecf20Sopenharmony_ci if (ret) { 12868c2ecf20Sopenharmony_ci drm_err(&dev_priv->drm, 12878c2ecf20Sopenharmony_ci "failed to set PCI D0 power state (%d)\n", ret); 12888c2ecf20Sopenharmony_ci return ret; 12898c2ecf20Sopenharmony_ci } 12908c2ecf20Sopenharmony_ci 12918c2ecf20Sopenharmony_ci /* 12928c2ecf20Sopenharmony_ci * Note that pci_enable_device() first enables any parent bridge 12938c2ecf20Sopenharmony_ci * device and only then sets the power state for this device. The 12948c2ecf20Sopenharmony_ci * bridge enabling is a nop though, since bridge devices are resumed 12958c2ecf20Sopenharmony_ci * first. The order of enabling power and enabling the device is 12968c2ecf20Sopenharmony_ci * imposed by the PCI core as described above, so here we preserve the 12978c2ecf20Sopenharmony_ci * same order for the freeze/thaw phases. 12988c2ecf20Sopenharmony_ci * 12998c2ecf20Sopenharmony_ci * TODO: eventually we should remove pci_disable_device() / 13008c2ecf20Sopenharmony_ci * pci_enable_enable_device() from suspend/resume. Due to how they 13018c2ecf20Sopenharmony_ci * depend on the device enable refcount we can't anyway depend on them 13028c2ecf20Sopenharmony_ci * disabling/enabling the device. 13038c2ecf20Sopenharmony_ci */ 13048c2ecf20Sopenharmony_ci if (pci_enable_device(pdev)) 13058c2ecf20Sopenharmony_ci return -EIO; 13068c2ecf20Sopenharmony_ci 13078c2ecf20Sopenharmony_ci pci_set_master(pdev); 13088c2ecf20Sopenharmony_ci 13098c2ecf20Sopenharmony_ci disable_rpm_wakeref_asserts(&dev_priv->runtime_pm); 13108c2ecf20Sopenharmony_ci 13118c2ecf20Sopenharmony_ci ret = vlv_resume_prepare(dev_priv, false); 13128c2ecf20Sopenharmony_ci if (ret) 13138c2ecf20Sopenharmony_ci drm_err(&dev_priv->drm, 13148c2ecf20Sopenharmony_ci "Resume prepare failed: %d, continuing anyway\n", ret); 13158c2ecf20Sopenharmony_ci 13168c2ecf20Sopenharmony_ci intel_uncore_resume_early(&dev_priv->uncore); 13178c2ecf20Sopenharmony_ci 13188c2ecf20Sopenharmony_ci intel_gt_check_and_clear_faults(&dev_priv->gt); 13198c2ecf20Sopenharmony_ci 13208c2ecf20Sopenharmony_ci intel_display_power_resume_early(dev_priv); 13218c2ecf20Sopenharmony_ci 13228c2ecf20Sopenharmony_ci intel_power_domains_resume(dev_priv); 13238c2ecf20Sopenharmony_ci 13248c2ecf20Sopenharmony_ci enable_rpm_wakeref_asserts(&dev_priv->runtime_pm); 13258c2ecf20Sopenharmony_ci 13268c2ecf20Sopenharmony_ci return ret; 13278c2ecf20Sopenharmony_ci} 13288c2ecf20Sopenharmony_ci 13298c2ecf20Sopenharmony_ciint i915_resume_switcheroo(struct drm_i915_private *i915) 13308c2ecf20Sopenharmony_ci{ 13318c2ecf20Sopenharmony_ci int ret; 13328c2ecf20Sopenharmony_ci 13338c2ecf20Sopenharmony_ci if (i915->drm.switch_power_state == DRM_SWITCH_POWER_OFF) 13348c2ecf20Sopenharmony_ci return 0; 13358c2ecf20Sopenharmony_ci 13368c2ecf20Sopenharmony_ci ret = i915_drm_resume_early(&i915->drm); 13378c2ecf20Sopenharmony_ci if (ret) 13388c2ecf20Sopenharmony_ci return ret; 13398c2ecf20Sopenharmony_ci 13408c2ecf20Sopenharmony_ci return i915_drm_resume(&i915->drm); 13418c2ecf20Sopenharmony_ci} 13428c2ecf20Sopenharmony_ci 13438c2ecf20Sopenharmony_cistatic int i915_pm_prepare(struct device *kdev) 13448c2ecf20Sopenharmony_ci{ 13458c2ecf20Sopenharmony_ci struct drm_i915_private *i915 = kdev_to_i915(kdev); 13468c2ecf20Sopenharmony_ci 13478c2ecf20Sopenharmony_ci if (!i915) { 13488c2ecf20Sopenharmony_ci dev_err(kdev, "DRM not initialized, aborting suspend.\n"); 13498c2ecf20Sopenharmony_ci return -ENODEV; 13508c2ecf20Sopenharmony_ci } 13518c2ecf20Sopenharmony_ci 13528c2ecf20Sopenharmony_ci if (i915->drm.switch_power_state == DRM_SWITCH_POWER_OFF) 13538c2ecf20Sopenharmony_ci return 0; 13548c2ecf20Sopenharmony_ci 13558c2ecf20Sopenharmony_ci return i915_drm_prepare(&i915->drm); 13568c2ecf20Sopenharmony_ci} 13578c2ecf20Sopenharmony_ci 13588c2ecf20Sopenharmony_cistatic int i915_pm_suspend(struct device *kdev) 13598c2ecf20Sopenharmony_ci{ 13608c2ecf20Sopenharmony_ci struct drm_i915_private *i915 = kdev_to_i915(kdev); 13618c2ecf20Sopenharmony_ci 13628c2ecf20Sopenharmony_ci if (!i915) { 13638c2ecf20Sopenharmony_ci dev_err(kdev, "DRM not initialized, aborting suspend.\n"); 13648c2ecf20Sopenharmony_ci return -ENODEV; 13658c2ecf20Sopenharmony_ci } 13668c2ecf20Sopenharmony_ci 13678c2ecf20Sopenharmony_ci if (i915->drm.switch_power_state == DRM_SWITCH_POWER_OFF) 13688c2ecf20Sopenharmony_ci return 0; 13698c2ecf20Sopenharmony_ci 13708c2ecf20Sopenharmony_ci return i915_drm_suspend(&i915->drm); 13718c2ecf20Sopenharmony_ci} 13728c2ecf20Sopenharmony_ci 13738c2ecf20Sopenharmony_cistatic int i915_pm_suspend_late(struct device *kdev) 13748c2ecf20Sopenharmony_ci{ 13758c2ecf20Sopenharmony_ci struct drm_i915_private *i915 = kdev_to_i915(kdev); 13768c2ecf20Sopenharmony_ci 13778c2ecf20Sopenharmony_ci /* 13788c2ecf20Sopenharmony_ci * We have a suspend ordering issue with the snd-hda driver also 13798c2ecf20Sopenharmony_ci * requiring our device to be power up. Due to the lack of a 13808c2ecf20Sopenharmony_ci * parent/child relationship we currently solve this with an late 13818c2ecf20Sopenharmony_ci * suspend hook. 13828c2ecf20Sopenharmony_ci * 13838c2ecf20Sopenharmony_ci * FIXME: This should be solved with a special hdmi sink device or 13848c2ecf20Sopenharmony_ci * similar so that power domains can be employed. 13858c2ecf20Sopenharmony_ci */ 13868c2ecf20Sopenharmony_ci if (i915->drm.switch_power_state == DRM_SWITCH_POWER_OFF) 13878c2ecf20Sopenharmony_ci return 0; 13888c2ecf20Sopenharmony_ci 13898c2ecf20Sopenharmony_ci return i915_drm_suspend_late(&i915->drm, false); 13908c2ecf20Sopenharmony_ci} 13918c2ecf20Sopenharmony_ci 13928c2ecf20Sopenharmony_cistatic int i915_pm_poweroff_late(struct device *kdev) 13938c2ecf20Sopenharmony_ci{ 13948c2ecf20Sopenharmony_ci struct drm_i915_private *i915 = kdev_to_i915(kdev); 13958c2ecf20Sopenharmony_ci 13968c2ecf20Sopenharmony_ci if (i915->drm.switch_power_state == DRM_SWITCH_POWER_OFF) 13978c2ecf20Sopenharmony_ci return 0; 13988c2ecf20Sopenharmony_ci 13998c2ecf20Sopenharmony_ci return i915_drm_suspend_late(&i915->drm, true); 14008c2ecf20Sopenharmony_ci} 14018c2ecf20Sopenharmony_ci 14028c2ecf20Sopenharmony_cistatic int i915_pm_resume_early(struct device *kdev) 14038c2ecf20Sopenharmony_ci{ 14048c2ecf20Sopenharmony_ci struct drm_i915_private *i915 = kdev_to_i915(kdev); 14058c2ecf20Sopenharmony_ci 14068c2ecf20Sopenharmony_ci if (i915->drm.switch_power_state == DRM_SWITCH_POWER_OFF) 14078c2ecf20Sopenharmony_ci return 0; 14088c2ecf20Sopenharmony_ci 14098c2ecf20Sopenharmony_ci return i915_drm_resume_early(&i915->drm); 14108c2ecf20Sopenharmony_ci} 14118c2ecf20Sopenharmony_ci 14128c2ecf20Sopenharmony_cistatic int i915_pm_resume(struct device *kdev) 14138c2ecf20Sopenharmony_ci{ 14148c2ecf20Sopenharmony_ci struct drm_i915_private *i915 = kdev_to_i915(kdev); 14158c2ecf20Sopenharmony_ci 14168c2ecf20Sopenharmony_ci if (i915->drm.switch_power_state == DRM_SWITCH_POWER_OFF) 14178c2ecf20Sopenharmony_ci return 0; 14188c2ecf20Sopenharmony_ci 14198c2ecf20Sopenharmony_ci return i915_drm_resume(&i915->drm); 14208c2ecf20Sopenharmony_ci} 14218c2ecf20Sopenharmony_ci 14228c2ecf20Sopenharmony_ci/* freeze: before creating the hibernation_image */ 14238c2ecf20Sopenharmony_cistatic int i915_pm_freeze(struct device *kdev) 14248c2ecf20Sopenharmony_ci{ 14258c2ecf20Sopenharmony_ci struct drm_i915_private *i915 = kdev_to_i915(kdev); 14268c2ecf20Sopenharmony_ci int ret; 14278c2ecf20Sopenharmony_ci 14288c2ecf20Sopenharmony_ci if (i915->drm.switch_power_state != DRM_SWITCH_POWER_OFF) { 14298c2ecf20Sopenharmony_ci ret = i915_drm_suspend(&i915->drm); 14308c2ecf20Sopenharmony_ci if (ret) 14318c2ecf20Sopenharmony_ci return ret; 14328c2ecf20Sopenharmony_ci } 14338c2ecf20Sopenharmony_ci 14348c2ecf20Sopenharmony_ci ret = i915_gem_freeze(i915); 14358c2ecf20Sopenharmony_ci if (ret) 14368c2ecf20Sopenharmony_ci return ret; 14378c2ecf20Sopenharmony_ci 14388c2ecf20Sopenharmony_ci return 0; 14398c2ecf20Sopenharmony_ci} 14408c2ecf20Sopenharmony_ci 14418c2ecf20Sopenharmony_cistatic int i915_pm_freeze_late(struct device *kdev) 14428c2ecf20Sopenharmony_ci{ 14438c2ecf20Sopenharmony_ci struct drm_i915_private *i915 = kdev_to_i915(kdev); 14448c2ecf20Sopenharmony_ci int ret; 14458c2ecf20Sopenharmony_ci 14468c2ecf20Sopenharmony_ci if (i915->drm.switch_power_state != DRM_SWITCH_POWER_OFF) { 14478c2ecf20Sopenharmony_ci ret = i915_drm_suspend_late(&i915->drm, true); 14488c2ecf20Sopenharmony_ci if (ret) 14498c2ecf20Sopenharmony_ci return ret; 14508c2ecf20Sopenharmony_ci } 14518c2ecf20Sopenharmony_ci 14528c2ecf20Sopenharmony_ci ret = i915_gem_freeze_late(i915); 14538c2ecf20Sopenharmony_ci if (ret) 14548c2ecf20Sopenharmony_ci return ret; 14558c2ecf20Sopenharmony_ci 14568c2ecf20Sopenharmony_ci return 0; 14578c2ecf20Sopenharmony_ci} 14588c2ecf20Sopenharmony_ci 14598c2ecf20Sopenharmony_ci/* thaw: called after creating the hibernation image, but before turning off. */ 14608c2ecf20Sopenharmony_cistatic int i915_pm_thaw_early(struct device *kdev) 14618c2ecf20Sopenharmony_ci{ 14628c2ecf20Sopenharmony_ci return i915_pm_resume_early(kdev); 14638c2ecf20Sopenharmony_ci} 14648c2ecf20Sopenharmony_ci 14658c2ecf20Sopenharmony_cistatic int i915_pm_thaw(struct device *kdev) 14668c2ecf20Sopenharmony_ci{ 14678c2ecf20Sopenharmony_ci return i915_pm_resume(kdev); 14688c2ecf20Sopenharmony_ci} 14698c2ecf20Sopenharmony_ci 14708c2ecf20Sopenharmony_ci/* restore: called after loading the hibernation image. */ 14718c2ecf20Sopenharmony_cistatic int i915_pm_restore_early(struct device *kdev) 14728c2ecf20Sopenharmony_ci{ 14738c2ecf20Sopenharmony_ci return i915_pm_resume_early(kdev); 14748c2ecf20Sopenharmony_ci} 14758c2ecf20Sopenharmony_ci 14768c2ecf20Sopenharmony_cistatic int i915_pm_restore(struct device *kdev) 14778c2ecf20Sopenharmony_ci{ 14788c2ecf20Sopenharmony_ci return i915_pm_resume(kdev); 14798c2ecf20Sopenharmony_ci} 14808c2ecf20Sopenharmony_ci 14818c2ecf20Sopenharmony_cistatic int intel_runtime_suspend(struct device *kdev) 14828c2ecf20Sopenharmony_ci{ 14838c2ecf20Sopenharmony_ci struct drm_i915_private *dev_priv = kdev_to_i915(kdev); 14848c2ecf20Sopenharmony_ci struct intel_runtime_pm *rpm = &dev_priv->runtime_pm; 14858c2ecf20Sopenharmony_ci int ret; 14868c2ecf20Sopenharmony_ci 14878c2ecf20Sopenharmony_ci if (drm_WARN_ON_ONCE(&dev_priv->drm, !HAS_RUNTIME_PM(dev_priv))) 14888c2ecf20Sopenharmony_ci return -ENODEV; 14898c2ecf20Sopenharmony_ci 14908c2ecf20Sopenharmony_ci drm_dbg_kms(&dev_priv->drm, "Suspending device\n"); 14918c2ecf20Sopenharmony_ci 14928c2ecf20Sopenharmony_ci disable_rpm_wakeref_asserts(rpm); 14938c2ecf20Sopenharmony_ci 14948c2ecf20Sopenharmony_ci /* 14958c2ecf20Sopenharmony_ci * We are safe here against re-faults, since the fault handler takes 14968c2ecf20Sopenharmony_ci * an RPM reference. 14978c2ecf20Sopenharmony_ci */ 14988c2ecf20Sopenharmony_ci i915_gem_runtime_suspend(dev_priv); 14998c2ecf20Sopenharmony_ci 15008c2ecf20Sopenharmony_ci intel_gt_runtime_suspend(&dev_priv->gt); 15018c2ecf20Sopenharmony_ci 15028c2ecf20Sopenharmony_ci intel_runtime_pm_disable_interrupts(dev_priv); 15038c2ecf20Sopenharmony_ci 15048c2ecf20Sopenharmony_ci intel_uncore_suspend(&dev_priv->uncore); 15058c2ecf20Sopenharmony_ci 15068c2ecf20Sopenharmony_ci intel_display_power_suspend(dev_priv); 15078c2ecf20Sopenharmony_ci 15088c2ecf20Sopenharmony_ci ret = vlv_suspend_complete(dev_priv); 15098c2ecf20Sopenharmony_ci if (ret) { 15108c2ecf20Sopenharmony_ci drm_err(&dev_priv->drm, 15118c2ecf20Sopenharmony_ci "Runtime suspend failed, disabling it (%d)\n", ret); 15128c2ecf20Sopenharmony_ci intel_uncore_runtime_resume(&dev_priv->uncore); 15138c2ecf20Sopenharmony_ci 15148c2ecf20Sopenharmony_ci intel_runtime_pm_enable_interrupts(dev_priv); 15158c2ecf20Sopenharmony_ci 15168c2ecf20Sopenharmony_ci intel_gt_runtime_resume(&dev_priv->gt); 15178c2ecf20Sopenharmony_ci 15188c2ecf20Sopenharmony_ci enable_rpm_wakeref_asserts(rpm); 15198c2ecf20Sopenharmony_ci 15208c2ecf20Sopenharmony_ci return ret; 15218c2ecf20Sopenharmony_ci } 15228c2ecf20Sopenharmony_ci 15238c2ecf20Sopenharmony_ci enable_rpm_wakeref_asserts(rpm); 15248c2ecf20Sopenharmony_ci intel_runtime_pm_driver_release(rpm); 15258c2ecf20Sopenharmony_ci 15268c2ecf20Sopenharmony_ci if (intel_uncore_arm_unclaimed_mmio_detection(&dev_priv->uncore)) 15278c2ecf20Sopenharmony_ci drm_err(&dev_priv->drm, 15288c2ecf20Sopenharmony_ci "Unclaimed access detected prior to suspending\n"); 15298c2ecf20Sopenharmony_ci 15308c2ecf20Sopenharmony_ci rpm->suspended = true; 15318c2ecf20Sopenharmony_ci 15328c2ecf20Sopenharmony_ci /* 15338c2ecf20Sopenharmony_ci * FIXME: We really should find a document that references the arguments 15348c2ecf20Sopenharmony_ci * used below! 15358c2ecf20Sopenharmony_ci */ 15368c2ecf20Sopenharmony_ci if (IS_BROADWELL(dev_priv)) { 15378c2ecf20Sopenharmony_ci /* 15388c2ecf20Sopenharmony_ci * On Broadwell, if we use PCI_D1 the PCH DDI ports will stop 15398c2ecf20Sopenharmony_ci * being detected, and the call we do at intel_runtime_resume() 15408c2ecf20Sopenharmony_ci * won't be able to restore them. Since PCI_D3hot matches the 15418c2ecf20Sopenharmony_ci * actual specification and appears to be working, use it. 15428c2ecf20Sopenharmony_ci */ 15438c2ecf20Sopenharmony_ci intel_opregion_notify_adapter(dev_priv, PCI_D3hot); 15448c2ecf20Sopenharmony_ci } else { 15458c2ecf20Sopenharmony_ci /* 15468c2ecf20Sopenharmony_ci * current versions of firmware which depend on this opregion 15478c2ecf20Sopenharmony_ci * notification have repurposed the D1 definition to mean 15488c2ecf20Sopenharmony_ci * "runtime suspended" vs. what you would normally expect (D3) 15498c2ecf20Sopenharmony_ci * to distinguish it from notifications that might be sent via 15508c2ecf20Sopenharmony_ci * the suspend path. 15518c2ecf20Sopenharmony_ci */ 15528c2ecf20Sopenharmony_ci intel_opregion_notify_adapter(dev_priv, PCI_D1); 15538c2ecf20Sopenharmony_ci } 15548c2ecf20Sopenharmony_ci 15558c2ecf20Sopenharmony_ci assert_forcewakes_inactive(&dev_priv->uncore); 15568c2ecf20Sopenharmony_ci 15578c2ecf20Sopenharmony_ci if (!IS_VALLEYVIEW(dev_priv) && !IS_CHERRYVIEW(dev_priv)) 15588c2ecf20Sopenharmony_ci intel_hpd_poll_init(dev_priv); 15598c2ecf20Sopenharmony_ci 15608c2ecf20Sopenharmony_ci drm_dbg_kms(&dev_priv->drm, "Device suspended\n"); 15618c2ecf20Sopenharmony_ci return 0; 15628c2ecf20Sopenharmony_ci} 15638c2ecf20Sopenharmony_ci 15648c2ecf20Sopenharmony_cistatic int intel_runtime_resume(struct device *kdev) 15658c2ecf20Sopenharmony_ci{ 15668c2ecf20Sopenharmony_ci struct drm_i915_private *dev_priv = kdev_to_i915(kdev); 15678c2ecf20Sopenharmony_ci struct intel_runtime_pm *rpm = &dev_priv->runtime_pm; 15688c2ecf20Sopenharmony_ci int ret; 15698c2ecf20Sopenharmony_ci 15708c2ecf20Sopenharmony_ci if (drm_WARN_ON_ONCE(&dev_priv->drm, !HAS_RUNTIME_PM(dev_priv))) 15718c2ecf20Sopenharmony_ci return -ENODEV; 15728c2ecf20Sopenharmony_ci 15738c2ecf20Sopenharmony_ci drm_dbg_kms(&dev_priv->drm, "Resuming device\n"); 15748c2ecf20Sopenharmony_ci 15758c2ecf20Sopenharmony_ci drm_WARN_ON_ONCE(&dev_priv->drm, atomic_read(&rpm->wakeref_count)); 15768c2ecf20Sopenharmony_ci disable_rpm_wakeref_asserts(rpm); 15778c2ecf20Sopenharmony_ci 15788c2ecf20Sopenharmony_ci intel_opregion_notify_adapter(dev_priv, PCI_D0); 15798c2ecf20Sopenharmony_ci rpm->suspended = false; 15808c2ecf20Sopenharmony_ci if (intel_uncore_unclaimed_mmio(&dev_priv->uncore)) 15818c2ecf20Sopenharmony_ci drm_dbg(&dev_priv->drm, 15828c2ecf20Sopenharmony_ci "Unclaimed access during suspend, bios?\n"); 15838c2ecf20Sopenharmony_ci 15848c2ecf20Sopenharmony_ci intel_display_power_resume(dev_priv); 15858c2ecf20Sopenharmony_ci 15868c2ecf20Sopenharmony_ci ret = vlv_resume_prepare(dev_priv, true); 15878c2ecf20Sopenharmony_ci 15888c2ecf20Sopenharmony_ci intel_uncore_runtime_resume(&dev_priv->uncore); 15898c2ecf20Sopenharmony_ci 15908c2ecf20Sopenharmony_ci intel_runtime_pm_enable_interrupts(dev_priv); 15918c2ecf20Sopenharmony_ci 15928c2ecf20Sopenharmony_ci /* 15938c2ecf20Sopenharmony_ci * No point of rolling back things in case of an error, as the best 15948c2ecf20Sopenharmony_ci * we can do is to hope that things will still work (and disable RPM). 15958c2ecf20Sopenharmony_ci */ 15968c2ecf20Sopenharmony_ci intel_gt_runtime_resume(&dev_priv->gt); 15978c2ecf20Sopenharmony_ci 15988c2ecf20Sopenharmony_ci /* 15998c2ecf20Sopenharmony_ci * On VLV/CHV display interrupts are part of the display 16008c2ecf20Sopenharmony_ci * power well, so hpd is reinitialized from there. For 16018c2ecf20Sopenharmony_ci * everyone else do it here. 16028c2ecf20Sopenharmony_ci */ 16038c2ecf20Sopenharmony_ci if (!IS_VALLEYVIEW(dev_priv) && !IS_CHERRYVIEW(dev_priv)) 16048c2ecf20Sopenharmony_ci intel_hpd_init(dev_priv); 16058c2ecf20Sopenharmony_ci 16068c2ecf20Sopenharmony_ci intel_enable_ipc(dev_priv); 16078c2ecf20Sopenharmony_ci 16088c2ecf20Sopenharmony_ci enable_rpm_wakeref_asserts(rpm); 16098c2ecf20Sopenharmony_ci 16108c2ecf20Sopenharmony_ci if (ret) 16118c2ecf20Sopenharmony_ci drm_err(&dev_priv->drm, 16128c2ecf20Sopenharmony_ci "Runtime resume failed, disabling it (%d)\n", ret); 16138c2ecf20Sopenharmony_ci else 16148c2ecf20Sopenharmony_ci drm_dbg_kms(&dev_priv->drm, "Device resumed\n"); 16158c2ecf20Sopenharmony_ci 16168c2ecf20Sopenharmony_ci return ret; 16178c2ecf20Sopenharmony_ci} 16188c2ecf20Sopenharmony_ci 16198c2ecf20Sopenharmony_ciconst struct dev_pm_ops i915_pm_ops = { 16208c2ecf20Sopenharmony_ci /* 16218c2ecf20Sopenharmony_ci * S0ix (via system suspend) and S3 event handlers [PMSG_SUSPEND, 16228c2ecf20Sopenharmony_ci * PMSG_RESUME] 16238c2ecf20Sopenharmony_ci */ 16248c2ecf20Sopenharmony_ci .prepare = i915_pm_prepare, 16258c2ecf20Sopenharmony_ci .suspend = i915_pm_suspend, 16268c2ecf20Sopenharmony_ci .suspend_late = i915_pm_suspend_late, 16278c2ecf20Sopenharmony_ci .resume_early = i915_pm_resume_early, 16288c2ecf20Sopenharmony_ci .resume = i915_pm_resume, 16298c2ecf20Sopenharmony_ci 16308c2ecf20Sopenharmony_ci /* 16318c2ecf20Sopenharmony_ci * S4 event handlers 16328c2ecf20Sopenharmony_ci * @freeze, @freeze_late : called (1) before creating the 16338c2ecf20Sopenharmony_ci * hibernation image [PMSG_FREEZE] and 16348c2ecf20Sopenharmony_ci * (2) after rebooting, before restoring 16358c2ecf20Sopenharmony_ci * the image [PMSG_QUIESCE] 16368c2ecf20Sopenharmony_ci * @thaw, @thaw_early : called (1) after creating the hibernation 16378c2ecf20Sopenharmony_ci * image, before writing it [PMSG_THAW] 16388c2ecf20Sopenharmony_ci * and (2) after failing to create or 16398c2ecf20Sopenharmony_ci * restore the image [PMSG_RECOVER] 16408c2ecf20Sopenharmony_ci * @poweroff, @poweroff_late: called after writing the hibernation 16418c2ecf20Sopenharmony_ci * image, before rebooting [PMSG_HIBERNATE] 16428c2ecf20Sopenharmony_ci * @restore, @restore_early : called after rebooting and restoring the 16438c2ecf20Sopenharmony_ci * hibernation image [PMSG_RESTORE] 16448c2ecf20Sopenharmony_ci */ 16458c2ecf20Sopenharmony_ci .freeze = i915_pm_freeze, 16468c2ecf20Sopenharmony_ci .freeze_late = i915_pm_freeze_late, 16478c2ecf20Sopenharmony_ci .thaw_early = i915_pm_thaw_early, 16488c2ecf20Sopenharmony_ci .thaw = i915_pm_thaw, 16498c2ecf20Sopenharmony_ci .poweroff = i915_pm_suspend, 16508c2ecf20Sopenharmony_ci .poweroff_late = i915_pm_poweroff_late, 16518c2ecf20Sopenharmony_ci .restore_early = i915_pm_restore_early, 16528c2ecf20Sopenharmony_ci .restore = i915_pm_restore, 16538c2ecf20Sopenharmony_ci 16548c2ecf20Sopenharmony_ci /* S0ix (via runtime suspend) event handlers */ 16558c2ecf20Sopenharmony_ci .runtime_suspend = intel_runtime_suspend, 16568c2ecf20Sopenharmony_ci .runtime_resume = intel_runtime_resume, 16578c2ecf20Sopenharmony_ci}; 16588c2ecf20Sopenharmony_ci 16598c2ecf20Sopenharmony_cistatic const struct file_operations i915_driver_fops = { 16608c2ecf20Sopenharmony_ci .owner = THIS_MODULE, 16618c2ecf20Sopenharmony_ci .open = drm_open, 16628c2ecf20Sopenharmony_ci .release = drm_release_noglobal, 16638c2ecf20Sopenharmony_ci .unlocked_ioctl = drm_ioctl, 16648c2ecf20Sopenharmony_ci .mmap = i915_gem_mmap, 16658c2ecf20Sopenharmony_ci .poll = drm_poll, 16668c2ecf20Sopenharmony_ci .read = drm_read, 16678c2ecf20Sopenharmony_ci .compat_ioctl = i915_ioc32_compat_ioctl, 16688c2ecf20Sopenharmony_ci .llseek = noop_llseek, 16698c2ecf20Sopenharmony_ci}; 16708c2ecf20Sopenharmony_ci 16718c2ecf20Sopenharmony_cistatic int 16728c2ecf20Sopenharmony_cii915_gem_reject_pin_ioctl(struct drm_device *dev, void *data, 16738c2ecf20Sopenharmony_ci struct drm_file *file) 16748c2ecf20Sopenharmony_ci{ 16758c2ecf20Sopenharmony_ci return -ENODEV; 16768c2ecf20Sopenharmony_ci} 16778c2ecf20Sopenharmony_ci 16788c2ecf20Sopenharmony_cistatic const struct drm_ioctl_desc i915_ioctls[] = { 16798c2ecf20Sopenharmony_ci DRM_IOCTL_DEF_DRV(I915_INIT, drm_noop, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), 16808c2ecf20Sopenharmony_ci DRM_IOCTL_DEF_DRV(I915_FLUSH, drm_noop, DRM_AUTH), 16818c2ecf20Sopenharmony_ci DRM_IOCTL_DEF_DRV(I915_FLIP, drm_noop, DRM_AUTH), 16828c2ecf20Sopenharmony_ci DRM_IOCTL_DEF_DRV(I915_BATCHBUFFER, drm_noop, DRM_AUTH), 16838c2ecf20Sopenharmony_ci DRM_IOCTL_DEF_DRV(I915_IRQ_EMIT, drm_noop, DRM_AUTH), 16848c2ecf20Sopenharmony_ci DRM_IOCTL_DEF_DRV(I915_IRQ_WAIT, drm_noop, DRM_AUTH), 16858c2ecf20Sopenharmony_ci DRM_IOCTL_DEF_DRV(I915_GETPARAM, i915_getparam_ioctl, DRM_RENDER_ALLOW), 16868c2ecf20Sopenharmony_ci DRM_IOCTL_DEF_DRV(I915_SETPARAM, drm_noop, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), 16878c2ecf20Sopenharmony_ci DRM_IOCTL_DEF_DRV(I915_ALLOC, drm_noop, DRM_AUTH), 16888c2ecf20Sopenharmony_ci DRM_IOCTL_DEF_DRV(I915_FREE, drm_noop, DRM_AUTH), 16898c2ecf20Sopenharmony_ci DRM_IOCTL_DEF_DRV(I915_INIT_HEAP, drm_noop, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), 16908c2ecf20Sopenharmony_ci DRM_IOCTL_DEF_DRV(I915_CMDBUFFER, drm_noop, DRM_AUTH), 16918c2ecf20Sopenharmony_ci DRM_IOCTL_DEF_DRV(I915_DESTROY_HEAP, drm_noop, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), 16928c2ecf20Sopenharmony_ci DRM_IOCTL_DEF_DRV(I915_SET_VBLANK_PIPE, drm_noop, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), 16938c2ecf20Sopenharmony_ci DRM_IOCTL_DEF_DRV(I915_GET_VBLANK_PIPE, drm_noop, DRM_AUTH), 16948c2ecf20Sopenharmony_ci DRM_IOCTL_DEF_DRV(I915_VBLANK_SWAP, drm_noop, DRM_AUTH), 16958c2ecf20Sopenharmony_ci DRM_IOCTL_DEF_DRV(I915_HWS_ADDR, drm_noop, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), 16968c2ecf20Sopenharmony_ci DRM_IOCTL_DEF_DRV(I915_GEM_INIT, drm_noop, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), 16978c2ecf20Sopenharmony_ci DRM_IOCTL_DEF_DRV(I915_GEM_EXECBUFFER, i915_gem_execbuffer_ioctl, DRM_AUTH), 16988c2ecf20Sopenharmony_ci DRM_IOCTL_DEF_DRV(I915_GEM_EXECBUFFER2_WR, i915_gem_execbuffer2_ioctl, DRM_RENDER_ALLOW), 16998c2ecf20Sopenharmony_ci DRM_IOCTL_DEF_DRV(I915_GEM_PIN, i915_gem_reject_pin_ioctl, DRM_AUTH|DRM_ROOT_ONLY), 17008c2ecf20Sopenharmony_ci DRM_IOCTL_DEF_DRV(I915_GEM_UNPIN, i915_gem_reject_pin_ioctl, DRM_AUTH|DRM_ROOT_ONLY), 17018c2ecf20Sopenharmony_ci DRM_IOCTL_DEF_DRV(I915_GEM_BUSY, i915_gem_busy_ioctl, DRM_RENDER_ALLOW), 17028c2ecf20Sopenharmony_ci DRM_IOCTL_DEF_DRV(I915_GEM_SET_CACHING, i915_gem_set_caching_ioctl, DRM_RENDER_ALLOW), 17038c2ecf20Sopenharmony_ci DRM_IOCTL_DEF_DRV(I915_GEM_GET_CACHING, i915_gem_get_caching_ioctl, DRM_RENDER_ALLOW), 17048c2ecf20Sopenharmony_ci DRM_IOCTL_DEF_DRV(I915_GEM_THROTTLE, i915_gem_throttle_ioctl, DRM_RENDER_ALLOW), 17058c2ecf20Sopenharmony_ci DRM_IOCTL_DEF_DRV(I915_GEM_ENTERVT, drm_noop, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), 17068c2ecf20Sopenharmony_ci DRM_IOCTL_DEF_DRV(I915_GEM_LEAVEVT, drm_noop, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), 17078c2ecf20Sopenharmony_ci DRM_IOCTL_DEF_DRV(I915_GEM_CREATE, i915_gem_create_ioctl, DRM_RENDER_ALLOW), 17088c2ecf20Sopenharmony_ci DRM_IOCTL_DEF_DRV(I915_GEM_PREAD, i915_gem_pread_ioctl, DRM_RENDER_ALLOW), 17098c2ecf20Sopenharmony_ci DRM_IOCTL_DEF_DRV(I915_GEM_PWRITE, i915_gem_pwrite_ioctl, DRM_RENDER_ALLOW), 17108c2ecf20Sopenharmony_ci DRM_IOCTL_DEF_DRV(I915_GEM_MMAP, i915_gem_mmap_ioctl, DRM_RENDER_ALLOW), 17118c2ecf20Sopenharmony_ci DRM_IOCTL_DEF_DRV(I915_GEM_MMAP_OFFSET, i915_gem_mmap_offset_ioctl, DRM_RENDER_ALLOW), 17128c2ecf20Sopenharmony_ci DRM_IOCTL_DEF_DRV(I915_GEM_SET_DOMAIN, i915_gem_set_domain_ioctl, DRM_RENDER_ALLOW), 17138c2ecf20Sopenharmony_ci DRM_IOCTL_DEF_DRV(I915_GEM_SW_FINISH, i915_gem_sw_finish_ioctl, DRM_RENDER_ALLOW), 17148c2ecf20Sopenharmony_ci DRM_IOCTL_DEF_DRV(I915_GEM_SET_TILING, i915_gem_set_tiling_ioctl, DRM_RENDER_ALLOW), 17158c2ecf20Sopenharmony_ci DRM_IOCTL_DEF_DRV(I915_GEM_GET_TILING, i915_gem_get_tiling_ioctl, DRM_RENDER_ALLOW), 17168c2ecf20Sopenharmony_ci DRM_IOCTL_DEF_DRV(I915_GEM_GET_APERTURE, i915_gem_get_aperture_ioctl, DRM_RENDER_ALLOW), 17178c2ecf20Sopenharmony_ci DRM_IOCTL_DEF_DRV(I915_GET_PIPE_FROM_CRTC_ID, intel_get_pipe_from_crtc_id_ioctl, 0), 17188c2ecf20Sopenharmony_ci DRM_IOCTL_DEF_DRV(I915_GEM_MADVISE, i915_gem_madvise_ioctl, DRM_RENDER_ALLOW), 17198c2ecf20Sopenharmony_ci DRM_IOCTL_DEF_DRV(I915_OVERLAY_PUT_IMAGE, intel_overlay_put_image_ioctl, DRM_MASTER), 17208c2ecf20Sopenharmony_ci DRM_IOCTL_DEF_DRV(I915_OVERLAY_ATTRS, intel_overlay_attrs_ioctl, DRM_MASTER), 17218c2ecf20Sopenharmony_ci DRM_IOCTL_DEF_DRV(I915_SET_SPRITE_COLORKEY, intel_sprite_set_colorkey_ioctl, DRM_MASTER), 17228c2ecf20Sopenharmony_ci DRM_IOCTL_DEF_DRV(I915_GET_SPRITE_COLORKEY, drm_noop, DRM_MASTER), 17238c2ecf20Sopenharmony_ci DRM_IOCTL_DEF_DRV(I915_GEM_WAIT, i915_gem_wait_ioctl, DRM_RENDER_ALLOW), 17248c2ecf20Sopenharmony_ci DRM_IOCTL_DEF_DRV(I915_GEM_CONTEXT_CREATE_EXT, i915_gem_context_create_ioctl, DRM_RENDER_ALLOW), 17258c2ecf20Sopenharmony_ci DRM_IOCTL_DEF_DRV(I915_GEM_CONTEXT_DESTROY, i915_gem_context_destroy_ioctl, DRM_RENDER_ALLOW), 17268c2ecf20Sopenharmony_ci DRM_IOCTL_DEF_DRV(I915_REG_READ, i915_reg_read_ioctl, DRM_RENDER_ALLOW), 17278c2ecf20Sopenharmony_ci DRM_IOCTL_DEF_DRV(I915_GET_RESET_STATS, i915_gem_context_reset_stats_ioctl, DRM_RENDER_ALLOW), 17288c2ecf20Sopenharmony_ci DRM_IOCTL_DEF_DRV(I915_GEM_USERPTR, i915_gem_userptr_ioctl, DRM_RENDER_ALLOW), 17298c2ecf20Sopenharmony_ci DRM_IOCTL_DEF_DRV(I915_GEM_CONTEXT_GETPARAM, i915_gem_context_getparam_ioctl, DRM_RENDER_ALLOW), 17308c2ecf20Sopenharmony_ci DRM_IOCTL_DEF_DRV(I915_GEM_CONTEXT_SETPARAM, i915_gem_context_setparam_ioctl, DRM_RENDER_ALLOW), 17318c2ecf20Sopenharmony_ci DRM_IOCTL_DEF_DRV(I915_PERF_OPEN, i915_perf_open_ioctl, DRM_RENDER_ALLOW), 17328c2ecf20Sopenharmony_ci DRM_IOCTL_DEF_DRV(I915_PERF_ADD_CONFIG, i915_perf_add_config_ioctl, DRM_RENDER_ALLOW), 17338c2ecf20Sopenharmony_ci DRM_IOCTL_DEF_DRV(I915_PERF_REMOVE_CONFIG, i915_perf_remove_config_ioctl, DRM_RENDER_ALLOW), 17348c2ecf20Sopenharmony_ci DRM_IOCTL_DEF_DRV(I915_QUERY, i915_query_ioctl, DRM_RENDER_ALLOW), 17358c2ecf20Sopenharmony_ci DRM_IOCTL_DEF_DRV(I915_GEM_VM_CREATE, i915_gem_vm_create_ioctl, DRM_RENDER_ALLOW), 17368c2ecf20Sopenharmony_ci DRM_IOCTL_DEF_DRV(I915_GEM_VM_DESTROY, i915_gem_vm_destroy_ioctl, DRM_RENDER_ALLOW), 17378c2ecf20Sopenharmony_ci}; 17388c2ecf20Sopenharmony_ci 17398c2ecf20Sopenharmony_cistatic struct drm_driver driver = { 17408c2ecf20Sopenharmony_ci /* Don't use MTRRs here; the Xserver or userspace app should 17418c2ecf20Sopenharmony_ci * deal with them for Intel hardware. 17428c2ecf20Sopenharmony_ci */ 17438c2ecf20Sopenharmony_ci .driver_features = 17448c2ecf20Sopenharmony_ci DRIVER_GEM | 17458c2ecf20Sopenharmony_ci DRIVER_RENDER | DRIVER_MODESET | DRIVER_ATOMIC | DRIVER_SYNCOBJ | 17468c2ecf20Sopenharmony_ci DRIVER_SYNCOBJ_TIMELINE, 17478c2ecf20Sopenharmony_ci .release = i915_driver_release, 17488c2ecf20Sopenharmony_ci .open = i915_driver_open, 17498c2ecf20Sopenharmony_ci .lastclose = i915_driver_lastclose, 17508c2ecf20Sopenharmony_ci .postclose = i915_driver_postclose, 17518c2ecf20Sopenharmony_ci 17528c2ecf20Sopenharmony_ci .gem_close_object = i915_gem_close_object, 17538c2ecf20Sopenharmony_ci .gem_free_object_unlocked = i915_gem_free_object, 17548c2ecf20Sopenharmony_ci 17558c2ecf20Sopenharmony_ci .prime_handle_to_fd = drm_gem_prime_handle_to_fd, 17568c2ecf20Sopenharmony_ci .prime_fd_to_handle = drm_gem_prime_fd_to_handle, 17578c2ecf20Sopenharmony_ci .gem_prime_export = i915_gem_prime_export, 17588c2ecf20Sopenharmony_ci .gem_prime_import = i915_gem_prime_import, 17598c2ecf20Sopenharmony_ci 17608c2ecf20Sopenharmony_ci .dumb_create = i915_gem_dumb_create, 17618c2ecf20Sopenharmony_ci .dumb_map_offset = i915_gem_dumb_mmap_offset, 17628c2ecf20Sopenharmony_ci 17638c2ecf20Sopenharmony_ci .ioctls = i915_ioctls, 17648c2ecf20Sopenharmony_ci .num_ioctls = ARRAY_SIZE(i915_ioctls), 17658c2ecf20Sopenharmony_ci .fops = &i915_driver_fops, 17668c2ecf20Sopenharmony_ci .name = DRIVER_NAME, 17678c2ecf20Sopenharmony_ci .desc = DRIVER_DESC, 17688c2ecf20Sopenharmony_ci .date = DRIVER_DATE, 17698c2ecf20Sopenharmony_ci .major = DRIVER_MAJOR, 17708c2ecf20Sopenharmony_ci .minor = DRIVER_MINOR, 17718c2ecf20Sopenharmony_ci .patchlevel = DRIVER_PATCHLEVEL, 17728c2ecf20Sopenharmony_ci}; 1773