diff options
Diffstat (limited to 'drivers')
| -rw-r--r-- | drivers/gpu/drm/i915/Kconfig.debug | 3 | ||||
| -rw-r--r-- | drivers/gpu/drm/i915/i915_debugfs.c | 6 | ||||
| -rw-r--r-- | drivers/gpu/drm/i915/i915_drv.c | 8 | ||||
| -rw-r--r-- | drivers/gpu/drm/i915/i915_drv.h | 20 | ||||
| -rw-r--r-- | drivers/gpu/drm/i915/intel_drv.h | 44 | ||||
| -rw-r--r-- | drivers/gpu/drm/i915/intel_runtime_pm.c | 285 | ||||
| -rw-r--r-- | drivers/gpu/drm/i915/selftests/mock_gem_device.c | 8 |
7 files changed, 324 insertions, 50 deletions
diff --git a/drivers/gpu/drm/i915/Kconfig.debug b/drivers/gpu/drm/i915/Kconfig.debug index 9e36ffb5eb7c..ad4d71161dda 100644 --- a/drivers/gpu/drm/i915/Kconfig.debug +++ b/drivers/gpu/drm/i915/Kconfig.debug | |||
| @@ -21,11 +21,11 @@ config DRM_I915_DEBUG | |||
| 21 | select DEBUG_FS | 21 | select DEBUG_FS |
| 22 | select PREEMPT_COUNT | 22 | select PREEMPT_COUNT |
| 23 | select I2C_CHARDEV | 23 | select I2C_CHARDEV |
| 24 | select STACKDEPOT | ||
| 24 | select DRM_DP_AUX_CHARDEV | 25 | select DRM_DP_AUX_CHARDEV |
| 25 | select X86_MSR # used by igt/pm_rpm | 26 | select X86_MSR # used by igt/pm_rpm |
| 26 | select DRM_VGEM # used by igt/prime_vgem (dmabuf interop checks) | 27 | select DRM_VGEM # used by igt/prime_vgem (dmabuf interop checks) |
| 27 | select DRM_DEBUG_MM if DRM=y | 28 | select DRM_DEBUG_MM if DRM=y |
| 28 | select STACKDEPOT if DRM=y # for DRM_DEBUG_MM | ||
| 29 | select DRM_DEBUG_SELFTEST | 29 | select DRM_DEBUG_SELFTEST |
| 30 | select SW_SYNC # signaling validation framework (igt/syncobj*) | 30 | select SW_SYNC # signaling validation framework (igt/syncobj*) |
| 31 | select DRM_I915_SW_FENCE_DEBUG_OBJECTS | 31 | select DRM_I915_SW_FENCE_DEBUG_OBJECTS |
| @@ -173,6 +173,7 @@ config DRM_I915_DEBUG_RUNTIME_PM | |||
| 173 | bool "Enable extra state checking for runtime PM" | 173 | bool "Enable extra state checking for runtime PM" |
| 174 | depends on DRM_I915 | 174 | depends on DRM_I915 |
| 175 | default n | 175 | default n |
| 176 | select STACKDEPOT | ||
| 176 | help | 177 | help |
| 177 | Choose this option to turn on extra state checking for the | 178 | Choose this option to turn on extra state checking for the |
| 178 | runtime PM functionality. This may introduce overhead during | 179 | runtime PM functionality. This may introduce overhead during |
diff --git a/drivers/gpu/drm/i915/i915_debugfs.c b/drivers/gpu/drm/i915/i915_debugfs.c index 95813e21ae02..050cf8abd426 100644 --- a/drivers/gpu/drm/i915/i915_debugfs.c +++ b/drivers/gpu/drm/i915/i915_debugfs.c | |||
| @@ -2702,6 +2702,12 @@ static int i915_runtime_pm_status(struct seq_file *m, void *unused) | |||
| 2702 | pci_power_name(pdev->current_state), | 2702 | pci_power_name(pdev->current_state), |
| 2703 | pdev->current_state); | 2703 | pdev->current_state); |
| 2704 | 2704 | ||
| 2705 | if (IS_ENABLED(CONFIG_DRM_I915_DEBUG_RUNTIME_PM)) { | ||
| 2706 | struct drm_printer p = drm_seq_file_printer(m); | ||
| 2707 | |||
| 2708 | print_intel_runtime_pm_wakeref(dev_priv, &p); | ||
| 2709 | } | ||
| 2710 | |||
| 2705 | return 0; | 2711 | return 0; |
| 2706 | } | 2712 | } |
| 2707 | 2713 | ||
diff --git a/drivers/gpu/drm/i915/i915_drv.c b/drivers/gpu/drm/i915/i915_drv.c index 75652dc1e24c..5731f992cf44 100644 --- a/drivers/gpu/drm/i915/i915_drv.c +++ b/drivers/gpu/drm/i915/i915_drv.c | |||
| @@ -905,6 +905,7 @@ static int i915_driver_init_early(struct drm_i915_private *dev_priv) | |||
| 905 | mutex_init(&dev_priv->pps_mutex); | 905 | mutex_init(&dev_priv->pps_mutex); |
| 906 | 906 | ||
| 907 | i915_memcpy_init_early(dev_priv); | 907 | i915_memcpy_init_early(dev_priv); |
| 908 | intel_runtime_pm_init_early(dev_priv); | ||
| 908 | 909 | ||
| 909 | ret = i915_workqueues_init(dev_priv); | 910 | ret = i915_workqueues_init(dev_priv); |
| 910 | if (ret < 0) | 911 | if (ret < 0) |
| @@ -1807,8 +1808,7 @@ void i915_driver_unload(struct drm_device *dev) | |||
| 1807 | i915_driver_cleanup_mmio(dev_priv); | 1808 | i915_driver_cleanup_mmio(dev_priv); |
| 1808 | 1809 | ||
| 1809 | enable_rpm_wakeref_asserts(dev_priv); | 1810 | enable_rpm_wakeref_asserts(dev_priv); |
| 1810 | 1811 | intel_runtime_pm_cleanup(dev_priv); | |
| 1811 | WARN_ON(atomic_read(&dev_priv->runtime_pm.wakeref_count)); | ||
| 1812 | } | 1812 | } |
| 1813 | 1813 | ||
| 1814 | static void i915_driver_release(struct drm_device *dev) | 1814 | static void i915_driver_release(struct drm_device *dev) |
| @@ -2010,6 +2010,8 @@ static int i915_drm_suspend_late(struct drm_device *dev, bool hibernation) | |||
| 2010 | 2010 | ||
| 2011 | out: | 2011 | out: |
| 2012 | enable_rpm_wakeref_asserts(dev_priv); | 2012 | enable_rpm_wakeref_asserts(dev_priv); |
| 2013 | if (!dev_priv->uncore.user_forcewake.count) | ||
| 2014 | intel_runtime_pm_cleanup(dev_priv); | ||
| 2013 | 2015 | ||
| 2014 | return ret; | 2016 | return ret; |
| 2015 | } | 2017 | } |
| @@ -2965,7 +2967,7 @@ static int intel_runtime_suspend(struct device *kdev) | |||
| 2965 | } | 2967 | } |
| 2966 | 2968 | ||
| 2967 | enable_rpm_wakeref_asserts(dev_priv); | 2969 | enable_rpm_wakeref_asserts(dev_priv); |
| 2968 | WARN_ON_ONCE(atomic_read(&dev_priv->runtime_pm.wakeref_count)); | 2970 | intel_runtime_pm_cleanup(dev_priv); |
| 2969 | 2971 | ||
| 2970 | if (intel_uncore_arm_unclaimed_mmio_detection(dev_priv)) | 2972 | if (intel_uncore_arm_unclaimed_mmio_detection(dev_priv)) |
| 2971 | DRM_ERROR("Unclaimed access detected prior to suspending\n"); | 2973 | DRM_ERROR("Unclaimed access detected prior to suspending\n"); |
diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 5df26ccda8a4..7e3566a0ba72 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h | |||
| @@ -45,6 +45,7 @@ | |||
| 45 | #include <linux/pm_qos.h> | 45 | #include <linux/pm_qos.h> |
| 46 | #include <linux/reservation.h> | 46 | #include <linux/reservation.h> |
| 47 | #include <linux/shmem_fs.h> | 47 | #include <linux/shmem_fs.h> |
| 48 | #include <linux/stackdepot.h> | ||
| 48 | 49 | ||
| 49 | #include <drm/intel-gtt.h> | 50 | #include <drm/intel-gtt.h> |
| 50 | #include <drm/drm_legacy.h> /* for struct drm_dma_handle */ | 51 | #include <drm/drm_legacy.h> /* for struct drm_dma_handle */ |
| @@ -1156,6 +1157,25 @@ struct i915_runtime_pm { | |||
| 1156 | atomic_t wakeref_count; | 1157 | atomic_t wakeref_count; |
| 1157 | bool suspended; | 1158 | bool suspended; |
| 1158 | bool irqs_enabled; | 1159 | bool irqs_enabled; |
| 1160 | |||
| 1161 | #if IS_ENABLED(CONFIG_DRM_I915_DEBUG_RUNTIME_PM) | ||
| 1162 | /* | ||
| 1163 | * To aide detection of wakeref leaks and general misuse, we | ||
| 1164 | * track all wakeref holders. With manual markup (i.e. returning | ||
| 1165 | * a cookie to each rpm_get caller which they then supply to their | ||
| 1166 | * paired rpm_put) we can remove corresponding pairs of and keep | ||
| 1167 | * the array trimmed to active wakerefs. | ||
| 1168 | */ | ||
| 1169 | struct intel_runtime_pm_debug { | ||
| 1170 | spinlock_t lock; | ||
| 1171 | |||
| 1172 | depot_stack_handle_t last_acquire; | ||
| 1173 | depot_stack_handle_t last_release; | ||
| 1174 | |||
| 1175 | depot_stack_handle_t *owners; | ||
| 1176 | unsigned long count; | ||
| 1177 | } debug; | ||
| 1178 | #endif | ||
| 1159 | }; | 1179 | }; |
| 1160 | 1180 | ||
| 1161 | enum intel_pipe_crc_source { | 1181 | enum intel_pipe_crc_source { |
diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index 1a11c2beb7f3..ac513fd70315 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h | |||
| @@ -41,6 +41,8 @@ | |||
| 41 | #include <drm/drm_atomic.h> | 41 | #include <drm/drm_atomic.h> |
| 42 | #include <media/cec-notifier.h> | 42 | #include <media/cec-notifier.h> |
| 43 | 43 | ||
| 44 | struct drm_printer; | ||
| 45 | |||
| 44 | /** | 46 | /** |
| 45 | * __wait_for - magic wait macro | 47 | * __wait_for - magic wait macro |
| 46 | * | 48 | * |
| @@ -2084,6 +2086,7 @@ bool intel_psr_enabled(struct intel_dp *intel_dp); | |||
| 2084 | void intel_init_quirks(struct drm_i915_private *dev_priv); | 2086 | void intel_init_quirks(struct drm_i915_private *dev_priv); |
| 2085 | 2087 | ||
| 2086 | /* intel_runtime_pm.c */ | 2088 | /* intel_runtime_pm.c */ |
| 2089 | void intel_runtime_pm_init_early(struct drm_i915_private *dev_priv); | ||
| 2087 | int intel_power_domains_init(struct drm_i915_private *); | 2090 | int intel_power_domains_init(struct drm_i915_private *); |
| 2088 | void intel_power_domains_cleanup(struct drm_i915_private *dev_priv); | 2091 | void intel_power_domains_cleanup(struct drm_i915_private *dev_priv); |
| 2089 | void intel_power_domains_init_hw(struct drm_i915_private *dev_priv, bool resume); | 2092 | void intel_power_domains_init_hw(struct drm_i915_private *dev_priv, bool resume); |
| @@ -2106,6 +2109,7 @@ void bxt_display_core_init(struct drm_i915_private *dev_priv, bool resume); | |||
| 2106 | void bxt_display_core_uninit(struct drm_i915_private *dev_priv); | 2109 | void bxt_display_core_uninit(struct drm_i915_private *dev_priv); |
| 2107 | void intel_runtime_pm_enable(struct drm_i915_private *dev_priv); | 2110 | void intel_runtime_pm_enable(struct drm_i915_private *dev_priv); |
| 2108 | void intel_runtime_pm_disable(struct drm_i915_private *dev_priv); | 2111 | void intel_runtime_pm_disable(struct drm_i915_private *dev_priv); |
| 2112 | void intel_runtime_pm_cleanup(struct drm_i915_private *dev_priv); | ||
| 2109 | const char * | 2113 | const char * |
| 2110 | intel_display_power_domain_str(enum intel_display_power_domain domain); | 2114 | intel_display_power_domain_str(enum intel_display_power_domain domain); |
| 2111 | 2115 | ||
| @@ -2123,23 +2127,23 @@ void icl_dbuf_slices_update(struct drm_i915_private *dev_priv, | |||
| 2123 | u8 req_slices); | 2127 | u8 req_slices); |
| 2124 | 2128 | ||
| 2125 | static inline void | 2129 | static inline void |
| 2126 | assert_rpm_device_not_suspended(struct drm_i915_private *dev_priv) | 2130 | assert_rpm_device_not_suspended(struct drm_i915_private *i915) |
| 2127 | { | 2131 | { |
| 2128 | WARN_ONCE(dev_priv->runtime_pm.suspended, | 2132 | WARN_ONCE(i915->runtime_pm.suspended, |
| 2129 | "Device suspended during HW access\n"); | 2133 | "Device suspended during HW access\n"); |
| 2130 | } | 2134 | } |
| 2131 | 2135 | ||
| 2132 | static inline void | 2136 | static inline void |
| 2133 | assert_rpm_wakelock_held(struct drm_i915_private *dev_priv) | 2137 | assert_rpm_wakelock_held(struct drm_i915_private *i915) |
| 2134 | { | 2138 | { |
| 2135 | assert_rpm_device_not_suspended(dev_priv); | 2139 | assert_rpm_device_not_suspended(i915); |
| 2136 | WARN_ONCE(!atomic_read(&dev_priv->runtime_pm.wakeref_count), | 2140 | WARN_ONCE(!atomic_read(&i915->runtime_pm.wakeref_count), |
| 2137 | "RPM wakelock ref not held during HW access"); | 2141 | "RPM wakelock ref not held during HW access"); |
| 2138 | } | 2142 | } |
| 2139 | 2143 | ||
| 2140 | /** | 2144 | /** |
| 2141 | * disable_rpm_wakeref_asserts - disable the RPM assert checks | 2145 | * disable_rpm_wakeref_asserts - disable the RPM assert checks |
| 2142 | * @dev_priv: i915 device instance | 2146 | * @i915: i915 device instance |
| 2143 | * | 2147 | * |
| 2144 | * This function disable asserts that check if we hold an RPM wakelock | 2148 | * This function disable asserts that check if we hold an RPM wakelock |
| 2145 | * reference, while keeping the device-not-suspended checks still enabled. | 2149 | * reference, while keeping the device-not-suspended checks still enabled. |
| @@ -2156,14 +2160,14 @@ assert_rpm_wakelock_held(struct drm_i915_private *dev_priv) | |||
| 2156 | * enable_rpm_wakeref_asserts(). | 2160 | * enable_rpm_wakeref_asserts(). |
| 2157 | */ | 2161 | */ |
| 2158 | static inline void | 2162 | static inline void |
| 2159 | disable_rpm_wakeref_asserts(struct drm_i915_private *dev_priv) | 2163 | disable_rpm_wakeref_asserts(struct drm_i915_private *i915) |
| 2160 | { | 2164 | { |
| 2161 | atomic_inc(&dev_priv->runtime_pm.wakeref_count); | 2165 | atomic_inc(&i915->runtime_pm.wakeref_count); |
| 2162 | } | 2166 | } |
| 2163 | 2167 | ||
| 2164 | /** | 2168 | /** |
| 2165 | * enable_rpm_wakeref_asserts - re-enable the RPM assert checks | 2169 | * enable_rpm_wakeref_asserts - re-enable the RPM assert checks |
| 2166 | * @dev_priv: i915 device instance | 2170 | * @i915: i915 device instance |
| 2167 | * | 2171 | * |
| 2168 | * This function re-enables the RPM assert checks after disabling them with | 2172 | * This function re-enables the RPM assert checks after disabling them with |
| 2169 | * disable_rpm_wakeref_asserts. It's meant to be used only in special | 2173 | * disable_rpm_wakeref_asserts. It's meant to be used only in special |
| @@ -2173,15 +2177,25 @@ disable_rpm_wakeref_asserts(struct drm_i915_private *dev_priv) | |||
| 2173 | * disable_rpm_wakeref_asserts(). | 2177 | * disable_rpm_wakeref_asserts(). |
| 2174 | */ | 2178 | */ |
| 2175 | static inline void | 2179 | static inline void |
| 2176 | enable_rpm_wakeref_asserts(struct drm_i915_private *dev_priv) | 2180 | enable_rpm_wakeref_asserts(struct drm_i915_private *i915) |
| 2177 | { | 2181 | { |
| 2178 | atomic_dec(&dev_priv->runtime_pm.wakeref_count); | 2182 | atomic_dec(&i915->runtime_pm.wakeref_count); |
| 2179 | } | 2183 | } |
| 2180 | 2184 | ||
| 2181 | void intel_runtime_pm_get(struct drm_i915_private *dev_priv); | 2185 | void intel_runtime_pm_get(struct drm_i915_private *i915); |
| 2182 | bool intel_runtime_pm_get_if_in_use(struct drm_i915_private *dev_priv); | 2186 | bool intel_runtime_pm_get_if_in_use(struct drm_i915_private *i915); |
| 2183 | void intel_runtime_pm_get_noresume(struct drm_i915_private *dev_priv); | 2187 | void intel_runtime_pm_get_noresume(struct drm_i915_private *i915); |
| 2184 | void intel_runtime_pm_put(struct drm_i915_private *dev_priv); | 2188 | void intel_runtime_pm_put(struct drm_i915_private *i915); |
| 2189 | |||
| 2190 | #if IS_ENABLED(CONFIG_DRM_I915_DEBUG_RUNTIME_PM) | ||
| 2191 | void print_intel_runtime_pm_wakeref(struct drm_i915_private *i915, | ||
| 2192 | struct drm_printer *p); | ||
| 2193 | #else | ||
| 2194 | static inline void print_intel_runtime_pm_wakeref(struct drm_i915_private *i915, | ||
| 2195 | struct drm_printer *p) | ||
| 2196 | { | ||
| 2197 | } | ||
| 2198 | #endif | ||
| 2185 | 2199 | ||
| 2186 | void chv_phy_powergate_lanes(struct intel_encoder *encoder, | 2200 | void chv_phy_powergate_lanes(struct intel_encoder *encoder, |
| 2187 | bool override, unsigned int mask); | 2201 | bool override, unsigned int mask); |
diff --git a/drivers/gpu/drm/i915/intel_runtime_pm.c b/drivers/gpu/drm/i915/intel_runtime_pm.c index 9e9501f82f06..08f809371bbd 100644 --- a/drivers/gpu/drm/i915/intel_runtime_pm.c +++ b/drivers/gpu/drm/i915/intel_runtime_pm.c | |||
| @@ -29,6 +29,8 @@ | |||
| 29 | #include <linux/pm_runtime.h> | 29 | #include <linux/pm_runtime.h> |
| 30 | #include <linux/vgaarb.h> | 30 | #include <linux/vgaarb.h> |
| 31 | 31 | ||
| 32 | #include <drm/drm_print.h> | ||
| 33 | |||
| 32 | #include "i915_drv.h" | 34 | #include "i915_drv.h" |
| 33 | #include "intel_drv.h" | 35 | #include "intel_drv.h" |
| 34 | 36 | ||
| @@ -49,6 +51,218 @@ | |||
| 49 | * present for a given platform. | 51 | * present for a given platform. |
| 50 | */ | 52 | */ |
| 51 | 53 | ||
| 54 | #if IS_ENABLED(CONFIG_DRM_I915_DEBUG_RUNTIME_PM) | ||
| 55 | |||
| 56 | #include <linux/sort.h> | ||
| 57 | |||
| 58 | #define STACKDEPTH 8 | ||
| 59 | |||
| 60 | static noinline depot_stack_handle_t __save_depot_stack(void) | ||
| 61 | { | ||
| 62 | unsigned long entries[STACKDEPTH]; | ||
| 63 | struct stack_trace trace = { | ||
| 64 | .entries = entries, | ||
| 65 | .max_entries = ARRAY_SIZE(entries), | ||
| 66 | .skip = 1, | ||
| 67 | }; | ||
| 68 | |||
| 69 | save_stack_trace(&trace); | ||
| 70 | if (trace.nr_entries && | ||
| 71 | trace.entries[trace.nr_entries - 1] == ULONG_MAX) | ||
| 72 | trace.nr_entries--; | ||
| 73 | |||
| 74 | return depot_save_stack(&trace, GFP_NOWAIT | __GFP_NOWARN); | ||
| 75 | } | ||
| 76 | |||
| 77 | static void __print_depot_stack(depot_stack_handle_t stack, | ||
| 78 | char *buf, int sz, int indent) | ||
| 79 | { | ||
| 80 | unsigned long entries[STACKDEPTH]; | ||
| 81 | struct stack_trace trace = { | ||
| 82 | .entries = entries, | ||
| 83 | .max_entries = ARRAY_SIZE(entries), | ||
| 84 | }; | ||
| 85 | |||
| 86 | depot_fetch_stack(stack, &trace); | ||
| 87 | snprint_stack_trace(buf, sz, &trace, indent); | ||
| 88 | } | ||
| 89 | |||
| 90 | static void init_intel_runtime_pm_wakeref(struct drm_i915_private *i915) | ||
| 91 | { | ||
| 92 | struct i915_runtime_pm *rpm = &i915->runtime_pm; | ||
| 93 | |||
| 94 | spin_lock_init(&rpm->debug.lock); | ||
| 95 | } | ||
| 96 | |||
| 97 | static noinline void | ||
| 98 | track_intel_runtime_pm_wakeref(struct drm_i915_private *i915) | ||
| 99 | { | ||
| 100 | struct i915_runtime_pm *rpm = &i915->runtime_pm; | ||
| 101 | depot_stack_handle_t stack, *stacks; | ||
| 102 | unsigned long flags; | ||
| 103 | |||
| 104 | atomic_inc(&rpm->wakeref_count); | ||
| 105 | assert_rpm_wakelock_held(i915); | ||
| 106 | |||
| 107 | if (!HAS_RUNTIME_PM(i915)) | ||
| 108 | return; | ||
| 109 | |||
| 110 | stack = __save_depot_stack(); | ||
| 111 | if (!stack) | ||
| 112 | return; | ||
| 113 | |||
| 114 | spin_lock_irqsave(&rpm->debug.lock, flags); | ||
| 115 | |||
| 116 | if (!rpm->debug.count) | ||
| 117 | rpm->debug.last_acquire = stack; | ||
| 118 | |||
| 119 | stacks = krealloc(rpm->debug.owners, | ||
| 120 | (rpm->debug.count + 1) * sizeof(*stacks), | ||
| 121 | GFP_NOWAIT | __GFP_NOWARN); | ||
| 122 | if (stacks) { | ||
| 123 | stacks[rpm->debug.count++] = stack; | ||
| 124 | rpm->debug.owners = stacks; | ||
| 125 | } | ||
| 126 | |||
| 127 | spin_unlock_irqrestore(&rpm->debug.lock, flags); | ||
| 128 | } | ||
| 129 | |||
| 130 | static int cmphandle(const void *_a, const void *_b) | ||
| 131 | { | ||
| 132 | const depot_stack_handle_t * const a = _a, * const b = _b; | ||
| 133 | |||
| 134 | if (*a < *b) | ||
| 135 | return -1; | ||
| 136 | else if (*a > *b) | ||
| 137 | return 1; | ||
| 138 | else | ||
| 139 | return 0; | ||
| 140 | } | ||
| 141 | |||
| 142 | static void | ||
| 143 | __print_intel_runtime_pm_wakeref(struct drm_printer *p, | ||
| 144 | const struct intel_runtime_pm_debug *dbg) | ||
| 145 | { | ||
| 146 | unsigned long i; | ||
| 147 | char *buf; | ||
| 148 | |||
| 149 | buf = kmalloc(PAGE_SIZE, GFP_KERNEL); | ||
| 150 | if (!buf) | ||
| 151 | return; | ||
| 152 | |||
| 153 | if (dbg->last_acquire) { | ||
| 154 | __print_depot_stack(dbg->last_acquire, buf, PAGE_SIZE, 2); | ||
| 155 | drm_printf(p, "Wakeref last acquired:\n%s", buf); | ||
| 156 | } | ||
| 157 | |||
| 158 | if (dbg->last_release) { | ||
| 159 | __print_depot_stack(dbg->last_release, buf, PAGE_SIZE, 2); | ||
| 160 | drm_printf(p, "Wakeref last released:\n%s", buf); | ||
| 161 | } | ||
| 162 | |||
| 163 | drm_printf(p, "Wakeref count: %lu\n", dbg->count); | ||
| 164 | |||
| 165 | sort(dbg->owners, dbg->count, sizeof(*dbg->owners), cmphandle, NULL); | ||
| 166 | |||
| 167 | for (i = 0; i < dbg->count; i++) { | ||
| 168 | depot_stack_handle_t stack = dbg->owners[i]; | ||
| 169 | unsigned long rep; | ||
| 170 | |||
| 171 | rep = 1; | ||
| 172 | while (i + 1 < dbg->count && dbg->owners[i + 1] == stack) | ||
| 173 | rep++, i++; | ||
| 174 | __print_depot_stack(stack, buf, PAGE_SIZE, 2); | ||
| 175 | drm_printf(p, "Wakeref x%lu taken at:\n%s", rep, buf); | ||
| 176 | } | ||
| 177 | |||
| 178 | kfree(buf); | ||
| 179 | } | ||
| 180 | |||
| 181 | static noinline void | ||
| 182 | untrack_intel_runtime_pm_wakeref(struct drm_i915_private *i915) | ||
| 183 | { | ||
| 184 | struct i915_runtime_pm *rpm = &i915->runtime_pm; | ||
| 185 | struct intel_runtime_pm_debug dbg = {}; | ||
| 186 | struct drm_printer p; | ||
| 187 | unsigned long flags; | ||
| 188 | |||
| 189 | assert_rpm_wakelock_held(i915); | ||
| 190 | if (atomic_dec_and_lock_irqsave(&rpm->wakeref_count, | ||
| 191 | &rpm->debug.lock, | ||
| 192 | flags)) { | ||
| 193 | dbg = rpm->debug; | ||
| 194 | |||
| 195 | rpm->debug.owners = NULL; | ||
| 196 | rpm->debug.count = 0; | ||
| 197 | rpm->debug.last_release = __save_depot_stack(); | ||
| 198 | |||
| 199 | spin_unlock_irqrestore(&rpm->debug.lock, flags); | ||
| 200 | } | ||
| 201 | if (!dbg.count) | ||
| 202 | return; | ||
| 203 | |||
| 204 | p = drm_debug_printer("i915"); | ||
| 205 | __print_intel_runtime_pm_wakeref(&p, &dbg); | ||
| 206 | |||
| 207 | kfree(dbg.owners); | ||
| 208 | } | ||
| 209 | |||
| 210 | void print_intel_runtime_pm_wakeref(struct drm_i915_private *i915, | ||
| 211 | struct drm_printer *p) | ||
| 212 | { | ||
| 213 | struct intel_runtime_pm_debug dbg = {}; | ||
| 214 | |||
| 215 | do { | ||
| 216 | struct i915_runtime_pm *rpm = &i915->runtime_pm; | ||
| 217 | unsigned long alloc = dbg.count; | ||
| 218 | depot_stack_handle_t *s; | ||
| 219 | |||
| 220 | spin_lock_irq(&rpm->debug.lock); | ||
| 221 | dbg.count = rpm->debug.count; | ||
| 222 | if (dbg.count <= alloc) { | ||
| 223 | memcpy(dbg.owners, | ||
| 224 | rpm->debug.owners, | ||
| 225 | dbg.count * sizeof(*s)); | ||
| 226 | } | ||
| 227 | dbg.last_acquire = rpm->debug.last_acquire; | ||
| 228 | dbg.last_release = rpm->debug.last_release; | ||
| 229 | spin_unlock_irq(&rpm->debug.lock); | ||
| 230 | if (dbg.count <= alloc) | ||
| 231 | break; | ||
| 232 | |||
| 233 | s = krealloc(dbg.owners, dbg.count * sizeof(*s), GFP_KERNEL); | ||
| 234 | if (!s) | ||
| 235 | goto out; | ||
| 236 | |||
| 237 | dbg.owners = s; | ||
| 238 | } while (1); | ||
| 239 | |||
| 240 | __print_intel_runtime_pm_wakeref(p, &dbg); | ||
| 241 | |||
| 242 | out: | ||
| 243 | kfree(dbg.owners); | ||
| 244 | } | ||
| 245 | |||
| 246 | #else | ||
| 247 | |||
| 248 | static void init_intel_runtime_pm_wakeref(struct drm_i915_private *i915) | ||
| 249 | { | ||
| 250 | } | ||
| 251 | |||
| 252 | static void track_intel_runtime_pm_wakeref(struct drm_i915_private *i915) | ||
| 253 | { | ||
| 254 | atomic_inc(&i915->runtime_pm.wakeref_count); | ||
| 255 | assert_rpm_wakelock_held(i915); | ||
| 256 | } | ||
| 257 | |||
| 258 | static void untrack_intel_runtime_pm_wakeref(struct drm_i915_private *i915) | ||
| 259 | { | ||
| 260 | assert_rpm_wakelock_held(i915); | ||
| 261 | atomic_dec(&i915->runtime_pm.wakeref_count); | ||
| 262 | } | ||
| 263 | |||
| 264 | #endif | ||
| 265 | |||
| 52 | bool intel_display_power_well_is_enabled(struct drm_i915_private *dev_priv, | 266 | bool intel_display_power_well_is_enabled(struct drm_i915_private *dev_priv, |
| 53 | enum i915_power_well_id power_well_id); | 267 | enum i915_power_well_id power_well_id); |
| 54 | 268 | ||
| @@ -3986,7 +4200,7 @@ static void intel_power_domains_verify_state(struct drm_i915_private *dev_priv) | |||
| 3986 | 4200 | ||
| 3987 | /** | 4201 | /** |
| 3988 | * intel_runtime_pm_get - grab a runtime pm reference | 4202 | * intel_runtime_pm_get - grab a runtime pm reference |
| 3989 | * @dev_priv: i915 device instance | 4203 | * @i915: i915 device instance |
| 3990 | * | 4204 | * |
| 3991 | * This function grabs a device-level runtime pm reference (mostly used for GEM | 4205 | * This function grabs a device-level runtime pm reference (mostly used for GEM |
| 3992 | * code to ensure the GTT or GT is on) and ensures that it is powered up. | 4206 | * code to ensure the GTT or GT is on) and ensures that it is powered up. |
| @@ -3994,22 +4208,21 @@ static void intel_power_domains_verify_state(struct drm_i915_private *dev_priv) | |||
| 3994 | * Any runtime pm reference obtained by this function must have a symmetric | 4208 | * Any runtime pm reference obtained by this function must have a symmetric |
| 3995 | * call to intel_runtime_pm_put() to release the reference again. | 4209 | * call to intel_runtime_pm_put() to release the reference again. |
| 3996 | */ | 4210 | */ |
| 3997 | void intel_runtime_pm_get(struct drm_i915_private *dev_priv) | 4211 | void intel_runtime_pm_get(struct drm_i915_private *i915) |
| 3998 | { | 4212 | { |
| 3999 | struct pci_dev *pdev = dev_priv->drm.pdev; | 4213 | struct pci_dev *pdev = i915->drm.pdev; |
| 4000 | struct device *kdev = &pdev->dev; | 4214 | struct device *kdev = &pdev->dev; |
| 4001 | int ret; | 4215 | int ret; |
| 4002 | 4216 | ||
| 4003 | ret = pm_runtime_get_sync(kdev); | 4217 | ret = pm_runtime_get_sync(kdev); |
| 4004 | WARN_ONCE(ret < 0, "pm_runtime_get_sync() failed: %d\n", ret); | 4218 | WARN_ONCE(ret < 0, "pm_runtime_get_sync() failed: %d\n", ret); |
| 4005 | 4219 | ||
| 4006 | atomic_inc(&dev_priv->runtime_pm.wakeref_count); | 4220 | track_intel_runtime_pm_wakeref(i915); |
| 4007 | assert_rpm_wakelock_held(dev_priv); | ||
| 4008 | } | 4221 | } |
| 4009 | 4222 | ||
| 4010 | /** | 4223 | /** |
| 4011 | * intel_runtime_pm_get_if_in_use - grab a runtime pm reference if device in use | 4224 | * intel_runtime_pm_get_if_in_use - grab a runtime pm reference if device in use |
| 4012 | * @dev_priv: i915 device instance | 4225 | * @i915: i915 device instance |
| 4013 | * | 4226 | * |
| 4014 | * This function grabs a device-level runtime pm reference if the device is | 4227 | * This function grabs a device-level runtime pm reference if the device is |
| 4015 | * already in use and ensures that it is powered up. It is illegal to try | 4228 | * already in use and ensures that it is powered up. It is illegal to try |
| @@ -4020,10 +4233,10 @@ void intel_runtime_pm_get(struct drm_i915_private *dev_priv) | |||
| 4020 | * | 4233 | * |
| 4021 | * Returns: True if the wakeref was acquired, or False otherwise. | 4234 | * Returns: True if the wakeref was acquired, or False otherwise. |
| 4022 | */ | 4235 | */ |
| 4023 | bool intel_runtime_pm_get_if_in_use(struct drm_i915_private *dev_priv) | 4236 | bool intel_runtime_pm_get_if_in_use(struct drm_i915_private *i915) |
| 4024 | { | 4237 | { |
| 4025 | if (IS_ENABLED(CONFIG_PM)) { | 4238 | if (IS_ENABLED(CONFIG_PM)) { |
| 4026 | struct pci_dev *pdev = dev_priv->drm.pdev; | 4239 | struct pci_dev *pdev = i915->drm.pdev; |
| 4027 | struct device *kdev = &pdev->dev; | 4240 | struct device *kdev = &pdev->dev; |
| 4028 | 4241 | ||
| 4029 | /* | 4242 | /* |
| @@ -4036,15 +4249,14 @@ bool intel_runtime_pm_get_if_in_use(struct drm_i915_private *dev_priv) | |||
| 4036 | return false; | 4249 | return false; |
| 4037 | } | 4250 | } |
| 4038 | 4251 | ||
| 4039 | atomic_inc(&dev_priv->runtime_pm.wakeref_count); | 4252 | track_intel_runtime_pm_wakeref(i915); |
| 4040 | assert_rpm_wakelock_held(dev_priv); | ||
| 4041 | 4253 | ||
| 4042 | return true; | 4254 | return true; |
| 4043 | } | 4255 | } |
| 4044 | 4256 | ||
| 4045 | /** | 4257 | /** |
| 4046 | * intel_runtime_pm_get_noresume - grab a runtime pm reference | 4258 | * intel_runtime_pm_get_noresume - grab a runtime pm reference |
| 4047 | * @dev_priv: i915 device instance | 4259 | * @i915: i915 device instance |
| 4048 | * | 4260 | * |
| 4049 | * This function grabs a device-level runtime pm reference (mostly used for GEM | 4261 | * This function grabs a device-level runtime pm reference (mostly used for GEM |
| 4050 | * code to ensure the GTT or GT is on). | 4262 | * code to ensure the GTT or GT is on). |
| @@ -4059,32 +4271,31 @@ bool intel_runtime_pm_get_if_in_use(struct drm_i915_private *dev_priv) | |||
| 4059 | * Any runtime pm reference obtained by this function must have a symmetric | 4271 | * Any runtime pm reference obtained by this function must have a symmetric |
| 4060 | * call to intel_runtime_pm_put() to release the reference again. | 4272 | * call to intel_runtime_pm_put() to release the reference again. |
| 4061 | */ | 4273 | */ |
| 4062 | void intel_runtime_pm_get_noresume(struct drm_i915_private *dev_priv) | 4274 | void intel_runtime_pm_get_noresume(struct drm_i915_private *i915) |
| 4063 | { | 4275 | { |
| 4064 | struct pci_dev *pdev = dev_priv->drm.pdev; | 4276 | struct pci_dev *pdev = i915->drm.pdev; |
| 4065 | struct device *kdev = &pdev->dev; | 4277 | struct device *kdev = &pdev->dev; |
| 4066 | 4278 | ||
| 4067 | assert_rpm_wakelock_held(dev_priv); | 4279 | assert_rpm_wakelock_held(i915); |
| 4068 | pm_runtime_get_noresume(kdev); | 4280 | pm_runtime_get_noresume(kdev); |
| 4069 | 4281 | ||
| 4070 | atomic_inc(&dev_priv->runtime_pm.wakeref_count); | 4282 | track_intel_runtime_pm_wakeref(i915); |
| 4071 | } | 4283 | } |
| 4072 | 4284 | ||
| 4073 | /** | 4285 | /** |
| 4074 | * intel_runtime_pm_put - release a runtime pm reference | 4286 | * intel_runtime_pm_put - release a runtime pm reference |
| 4075 | * @dev_priv: i915 device instance | 4287 | * @i915: i915 device instance |
| 4076 | * | 4288 | * |
| 4077 | * This function drops the device-level runtime pm reference obtained by | 4289 | * This function drops the device-level runtime pm reference obtained by |
| 4078 | * intel_runtime_pm_get() and might power down the corresponding | 4290 | * intel_runtime_pm_get() and might power down the corresponding |
| 4079 | * hardware block right away if this is the last reference. | 4291 | * hardware block right away if this is the last reference. |
| 4080 | */ | 4292 | */ |
| 4081 | void intel_runtime_pm_put(struct drm_i915_private *dev_priv) | 4293 | void intel_runtime_pm_put(struct drm_i915_private *i915) |
| 4082 | { | 4294 | { |
| 4083 | struct pci_dev *pdev = dev_priv->drm.pdev; | 4295 | struct pci_dev *pdev = i915->drm.pdev; |
| 4084 | struct device *kdev = &pdev->dev; | 4296 | struct device *kdev = &pdev->dev; |
| 4085 | 4297 | ||
| 4086 | assert_rpm_wakelock_held(dev_priv); | 4298 | untrack_intel_runtime_pm_wakeref(i915); |
| 4087 | atomic_dec(&dev_priv->runtime_pm.wakeref_count); | ||
| 4088 | 4299 | ||
| 4089 | pm_runtime_mark_last_busy(kdev); | 4300 | pm_runtime_mark_last_busy(kdev); |
| 4090 | pm_runtime_put_autosuspend(kdev); | 4301 | pm_runtime_put_autosuspend(kdev); |
| @@ -4092,7 +4303,7 @@ void intel_runtime_pm_put(struct drm_i915_private *dev_priv) | |||
| 4092 | 4303 | ||
| 4093 | /** | 4304 | /** |
| 4094 | * intel_runtime_pm_enable - enable runtime pm | 4305 | * intel_runtime_pm_enable - enable runtime pm |
| 4095 | * @dev_priv: i915 device instance | 4306 | * @i915: i915 device instance |
| 4096 | * | 4307 | * |
| 4097 | * This function enables runtime pm at the end of the driver load sequence. | 4308 | * This function enables runtime pm at the end of the driver load sequence. |
| 4098 | * | 4309 | * |
| @@ -4100,9 +4311,9 @@ void intel_runtime_pm_put(struct drm_i915_private *dev_priv) | |||
| 4100 | * subordinate display power domains. That is done by | 4311 | * subordinate display power domains. That is done by |
| 4101 | * intel_power_domains_enable(). | 4312 | * intel_power_domains_enable(). |
| 4102 | */ | 4313 | */ |
| 4103 | void intel_runtime_pm_enable(struct drm_i915_private *dev_priv) | 4314 | void intel_runtime_pm_enable(struct drm_i915_private *i915) |
| 4104 | { | 4315 | { |
| 4105 | struct pci_dev *pdev = dev_priv->drm.pdev; | 4316 | struct pci_dev *pdev = i915->drm.pdev; |
| 4106 | struct device *kdev = &pdev->dev; | 4317 | struct device *kdev = &pdev->dev; |
| 4107 | 4318 | ||
| 4108 | /* | 4319 | /* |
| @@ -4124,7 +4335,7 @@ void intel_runtime_pm_enable(struct drm_i915_private *dev_priv) | |||
| 4124 | * so the driver's own RPM reference tracking asserts also work on | 4335 | * so the driver's own RPM reference tracking asserts also work on |
| 4125 | * platforms without RPM support. | 4336 | * platforms without RPM support. |
| 4126 | */ | 4337 | */ |
| 4127 | if (!HAS_RUNTIME_PM(dev_priv)) { | 4338 | if (!HAS_RUNTIME_PM(i915)) { |
| 4128 | int ret; | 4339 | int ret; |
| 4129 | 4340 | ||
| 4130 | pm_runtime_dont_use_autosuspend(kdev); | 4341 | pm_runtime_dont_use_autosuspend(kdev); |
| @@ -4142,17 +4353,35 @@ void intel_runtime_pm_enable(struct drm_i915_private *dev_priv) | |||
| 4142 | pm_runtime_put_autosuspend(kdev); | 4353 | pm_runtime_put_autosuspend(kdev); |
| 4143 | } | 4354 | } |
| 4144 | 4355 | ||
| 4145 | void intel_runtime_pm_disable(struct drm_i915_private *dev_priv) | 4356 | void intel_runtime_pm_disable(struct drm_i915_private *i915) |
| 4146 | { | 4357 | { |
| 4147 | struct pci_dev *pdev = dev_priv->drm.pdev; | 4358 | struct pci_dev *pdev = i915->drm.pdev; |
| 4148 | struct device *kdev = &pdev->dev; | 4359 | struct device *kdev = &pdev->dev; |
| 4149 | 4360 | ||
| 4150 | /* Transfer rpm ownership back to core */ | 4361 | /* Transfer rpm ownership back to core */ |
| 4151 | WARN(pm_runtime_get_sync(&dev_priv->drm.pdev->dev) < 0, | 4362 | WARN(pm_runtime_get_sync(kdev) < 0, |
| 4152 | "Failed to pass rpm ownership back to core\n"); | 4363 | "Failed to pass rpm ownership back to core\n"); |
| 4153 | 4364 | ||
| 4154 | pm_runtime_dont_use_autosuspend(kdev); | 4365 | pm_runtime_dont_use_autosuspend(kdev); |
| 4155 | 4366 | ||
| 4156 | if (!HAS_RUNTIME_PM(dev_priv)) | 4367 | if (!HAS_RUNTIME_PM(i915)) |
| 4157 | pm_runtime_put(kdev); | 4368 | pm_runtime_put(kdev); |
| 4158 | } | 4369 | } |
| 4370 | |||
| 4371 | void intel_runtime_pm_cleanup(struct drm_i915_private *i915) | ||
| 4372 | { | ||
| 4373 | struct i915_runtime_pm *rpm = &i915->runtime_pm; | ||
| 4374 | int count; | ||
| 4375 | |||
| 4376 | count = atomic_fetch_inc(&rpm->wakeref_count); /* balance untrack */ | ||
| 4377 | WARN(count, | ||
| 4378 | "i915->runtime_pm.wakeref_count=%d on cleanup\n", | ||
| 4379 | count); | ||
| 4380 | |||
| 4381 | untrack_intel_runtime_pm_wakeref(i915); | ||
| 4382 | } | ||
| 4383 | |||
| 4384 | void intel_runtime_pm_init_early(struct drm_i915_private *i915) | ||
| 4385 | { | ||
| 4386 | init_intel_runtime_pm_wakeref(i915); | ||
| 4387 | } | ||
diff --git a/drivers/gpu/drm/i915/selftests/mock_gem_device.c b/drivers/gpu/drm/i915/selftests/mock_gem_device.c index baa3c38919de..082809569681 100644 --- a/drivers/gpu/drm/i915/selftests/mock_gem_device.c +++ b/drivers/gpu/drm/i915/selftests/mock_gem_device.c | |||
| @@ -154,15 +154,17 @@ struct drm_i915_private *mock_gem_device(void) | |||
| 154 | pdev->dev.archdata.iommu = (void *)-1; | 154 | pdev->dev.archdata.iommu = (void *)-1; |
| 155 | #endif | 155 | #endif |
| 156 | 156 | ||
| 157 | i915 = (struct drm_i915_private *)(pdev + 1); | ||
| 158 | pci_set_drvdata(pdev, i915); | ||
| 159 | |||
| 160 | intel_runtime_pm_init_early(i915); | ||
| 161 | |||
| 157 | dev_pm_domain_set(&pdev->dev, &pm_domain); | 162 | dev_pm_domain_set(&pdev->dev, &pm_domain); |
| 158 | pm_runtime_enable(&pdev->dev); | 163 | pm_runtime_enable(&pdev->dev); |
| 159 | pm_runtime_dont_use_autosuspend(&pdev->dev); | 164 | pm_runtime_dont_use_autosuspend(&pdev->dev); |
| 160 | if (pm_runtime_enabled(&pdev->dev)) | 165 | if (pm_runtime_enabled(&pdev->dev)) |
| 161 | WARN_ON(pm_runtime_get_sync(&pdev->dev)); | 166 | WARN_ON(pm_runtime_get_sync(&pdev->dev)); |
| 162 | 167 | ||
| 163 | i915 = (struct drm_i915_private *)(pdev + 1); | ||
| 164 | pci_set_drvdata(pdev, i915); | ||
| 165 | |||
| 166 | err = drm_dev_init(&i915->drm, &mock_driver, &pdev->dev); | 168 | err = drm_dev_init(&i915->drm, &mock_driver, &pdev->dev); |
| 167 | if (err) { | 169 | if (err) { |
| 168 | pr_err("Failed to initialise mock GEM device: err=%d\n", err); | 170 | pr_err("Failed to initialise mock GEM device: err=%d\n", err); |
