i915_gem.c 5.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262
  1. /*
  2. * SPDX-License-Identifier: MIT
  3. *
  4. * Copyright © 2018 Intel Corporation
  5. */
  6. #include <linux/prandom.h>
  7. #include "gem/i915_gem_internal.h"
  8. #include "gem/i915_gem_pm.h"
  9. #include "gem/selftests/igt_gem_utils.h"
  10. #include "gem/selftests/mock_context.h"
  11. #include "gt/intel_gt.h"
  12. #include "gt/intel_gt_pm.h"
  13. #include "i915_selftest.h"
  14. #include "igt_flush_test.h"
  15. #include "mock_drm.h"
  16. static int switch_to_context(struct i915_gem_context *ctx)
  17. {
  18. struct i915_gem_engines_iter it;
  19. struct intel_context *ce;
  20. int err = 0;
  21. for_each_gem_engine(ce, i915_gem_context_lock_engines(ctx), it) {
  22. struct i915_request *rq;
  23. rq = intel_context_create_request(ce);
  24. if (IS_ERR(rq)) {
  25. err = PTR_ERR(rq);
  26. break;
  27. }
  28. i915_request_add(rq);
  29. }
  30. i915_gem_context_unlock_engines(ctx);
  31. return err;
  32. }
  33. static void trash_stolen(struct drm_i915_private *i915)
  34. {
  35. struct i915_ggtt *ggtt = to_gt(i915)->ggtt;
  36. const u64 slot = ggtt->error_capture.start;
  37. const resource_size_t size = resource_size(&i915->dsm.stolen);
  38. struct rnd_state prng;
  39. unsigned long page;
  40. /* XXX: fsck. needs some more thought... */
  41. if (!i915_ggtt_has_aperture(ggtt))
  42. return;
  43. prandom_seed_state(&prng, 0x12345678);
  44. for (page = 0; page < size; page += PAGE_SIZE) {
  45. const dma_addr_t dma = i915->dsm.stolen.start + page;
  46. u32 __iomem *s;
  47. int x;
  48. ggtt->vm.insert_page(&ggtt->vm, dma, slot,
  49. i915_gem_get_pat_index(i915,
  50. I915_CACHE_NONE),
  51. 0);
  52. s = io_mapping_map_atomic_wc(&ggtt->iomap, slot);
  53. for (x = 0; x < PAGE_SIZE / sizeof(u32); x++) {
  54. iowrite32(prandom_u32_state(&prng), &s[x]);
  55. }
  56. io_mapping_unmap_atomic(s);
  57. }
  58. ggtt->vm.clear_range(&ggtt->vm, slot, PAGE_SIZE);
  59. }
  60. static void simulate_hibernate(struct drm_i915_private *i915)
  61. {
  62. intel_wakeref_t wakeref;
  63. wakeref = intel_runtime_pm_get(&i915->runtime_pm);
  64. /*
  65. * As a final string in the tail, invalidate stolen. Under a real S4,
  66. * stolen is lost and needs to be refilled on resume. However, under
  67. * CI we merely do S4-device testing (as full S4 is too unreliable
  68. * for automated testing across a cluster), so to simulate the effect
  69. * of stolen being trashed across S4, we trash it ourselves.
  70. */
  71. trash_stolen(i915);
  72. intel_runtime_pm_put(&i915->runtime_pm, wakeref);
  73. }
  74. static int igt_pm_prepare(struct drm_i915_private *i915)
  75. {
  76. i915_gem_suspend(i915);
  77. return 0;
  78. }
  79. static void igt_pm_suspend(struct drm_i915_private *i915)
  80. {
  81. intel_wakeref_t wakeref;
  82. with_intel_runtime_pm(&i915->runtime_pm, wakeref) {
  83. i915_ggtt_suspend(to_gt(i915)->ggtt);
  84. i915_gem_suspend_late(i915);
  85. }
  86. }
  87. static void igt_pm_hibernate(struct drm_i915_private *i915)
  88. {
  89. intel_wakeref_t wakeref;
  90. with_intel_runtime_pm(&i915->runtime_pm, wakeref) {
  91. i915_ggtt_suspend(to_gt(i915)->ggtt);
  92. i915_gem_freeze(i915);
  93. i915_gem_freeze_late(i915);
  94. }
  95. }
  96. static void igt_pm_resume(struct drm_i915_private *i915)
  97. {
  98. intel_wakeref_t wakeref;
  99. /*
  100. * Both suspend and hibernate follow the same wakeup path and assume
  101. * that runtime-pm just works.
  102. */
  103. with_intel_runtime_pm(&i915->runtime_pm, wakeref) {
  104. i915_ggtt_resume(to_gt(i915)->ggtt);
  105. if (GRAPHICS_VER(i915) >= 8)
  106. setup_private_pat(to_gt(i915));
  107. i915_gem_resume(i915);
  108. }
  109. }
  110. static int igt_gem_suspend(void *arg)
  111. {
  112. struct drm_i915_private *i915 = arg;
  113. struct i915_gem_context *ctx;
  114. struct file *file;
  115. int err;
  116. file = mock_file(i915);
  117. if (IS_ERR(file))
  118. return PTR_ERR(file);
  119. err = -ENOMEM;
  120. ctx = live_context(i915, file);
  121. if (!IS_ERR(ctx))
  122. err = switch_to_context(ctx);
  123. if (err)
  124. goto out;
  125. err = igt_pm_prepare(i915);
  126. if (err)
  127. goto out;
  128. igt_pm_suspend(i915);
  129. /* Here be dragons! Note that with S3RST any S3 may become S4! */
  130. simulate_hibernate(i915);
  131. igt_pm_resume(i915);
  132. err = switch_to_context(ctx);
  133. out:
  134. fput(file);
  135. return err;
  136. }
  137. static int igt_gem_hibernate(void *arg)
  138. {
  139. struct drm_i915_private *i915 = arg;
  140. struct i915_gem_context *ctx;
  141. struct file *file;
  142. int err;
  143. file = mock_file(i915);
  144. if (IS_ERR(file))
  145. return PTR_ERR(file);
  146. err = -ENOMEM;
  147. ctx = live_context(i915, file);
  148. if (!IS_ERR(ctx))
  149. err = switch_to_context(ctx);
  150. if (err)
  151. goto out;
  152. err = igt_pm_prepare(i915);
  153. if (err)
  154. goto out;
  155. igt_pm_hibernate(i915);
  156. /* Here be dragons! */
  157. simulate_hibernate(i915);
  158. igt_pm_resume(i915);
  159. err = switch_to_context(ctx);
  160. out:
  161. fput(file);
  162. return err;
  163. }
  164. static int igt_gem_ww_ctx(void *arg)
  165. {
  166. struct drm_i915_private *i915 = arg;
  167. struct drm_i915_gem_object *obj, *obj2;
  168. struct i915_gem_ww_ctx ww;
  169. int err = 0;
  170. obj = i915_gem_object_create_internal(i915, PAGE_SIZE);
  171. if (IS_ERR(obj))
  172. return PTR_ERR(obj);
  173. obj2 = i915_gem_object_create_internal(i915, PAGE_SIZE);
  174. if (IS_ERR(obj2)) {
  175. err = PTR_ERR(obj2);
  176. goto put1;
  177. }
  178. i915_gem_ww_ctx_init(&ww, true);
  179. retry:
  180. /* Lock the objects, twice for good measure (-EALREADY handling) */
  181. err = i915_gem_object_lock(obj, &ww);
  182. if (!err)
  183. err = i915_gem_object_lock_interruptible(obj, &ww);
  184. if (!err)
  185. err = i915_gem_object_lock_interruptible(obj2, &ww);
  186. if (!err)
  187. err = i915_gem_object_lock(obj2, &ww);
  188. if (err == -EDEADLK) {
  189. err = i915_gem_ww_ctx_backoff(&ww);
  190. if (!err)
  191. goto retry;
  192. }
  193. i915_gem_ww_ctx_fini(&ww);
  194. i915_gem_object_put(obj2);
  195. put1:
  196. i915_gem_object_put(obj);
  197. return err;
  198. }
  199. int i915_gem_live_selftests(struct drm_i915_private *i915)
  200. {
  201. static const struct i915_subtest tests[] = {
  202. SUBTEST(igt_gem_suspend),
  203. SUBTEST(igt_gem_hibernate),
  204. SUBTEST(igt_gem_ww_ctx),
  205. };
  206. if (intel_gt_is_wedged(to_gt(i915)))
  207. return 0;
  208. return i915_live_subtests(tests, i915);
  209. }