Branch data Line data Source code
1 : : /* 2 : : * SPDX-License-Identifier: MIT 3 : : * 4 : : * Copyright © 2019 Intel Corporation 5 : : */ 6 : : 7 : : #include "gem/i915_gem_pm.h" 8 : : #include "gt/intel_gt.h" 9 : : #include "gt/intel_gt_pm.h" 10 : : #include "gt/intel_gt_requests.h" 11 : : 12 : : #include "i915_drv.h" 13 : : 14 : 0 : void i915_gem_suspend(struct drm_i915_private *i915) 15 : : { 16 : 0 : GEM_TRACE("%s\n", dev_name(i915->drm.dev)); 17 : : 18 : 0 : intel_wakeref_auto(&i915->ggtt.userfault_wakeref, 0); 19 : 0 : flush_workqueue(i915->wq); 20 : : 21 : : /* 22 : : * We have to flush all the executing contexts to main memory so 23 : : * that they can saved in the hibernation image. To ensure the last 24 : : * context image is coherent, we have to switch away from it. That 25 : : * leaves the i915->kernel_context still active when 26 : : * we actually suspend, and its image in memory may not match the GPU 27 : : * state. Fortunately, the kernel_context is disposable and we do 28 : : * not rely on its state. 29 : : */ 30 : 0 : intel_gt_suspend_prepare(&i915->gt); 31 : : 32 : 0 : i915_gem_drain_freed_objects(i915); 33 : 0 : } 34 : : 35 : 0 : static struct drm_i915_gem_object *first_mm_object(struct list_head *list) 36 : : { 37 : 0 : return list_first_entry_or_null(list, 38 : : struct drm_i915_gem_object, 39 : : mm.link); 40 : : } 41 : : 42 : 0 : void i915_gem_suspend_late(struct drm_i915_private *i915) 43 : : { 44 : 0 : struct drm_i915_gem_object *obj; 45 : 0 : struct list_head *phases[] = { 46 : 0 : &i915->mm.shrink_list, 47 : 0 : &i915->mm.purge_list, 48 : : NULL 49 : : }, **phase; 50 : 0 : unsigned long flags; 51 : : 52 : : /* 53 : : * Neither the BIOS, ourselves or any other kernel 54 : : * expects the system to be in execlists mode on startup, 55 : : * so we need to reset the GPU back to legacy mode. And the only 56 : : * known way to disable logical contexts is through a GPU reset. 57 : : * 58 : : * So in order to leave the system in a known default configuration, 59 : : * always reset the GPU upon unload and suspend. Afterwards we then 60 : : * clean up the GEM state tracking, flushing off the requests and 61 : : * leaving the system in a known idle state. 62 : : * 63 : : * Note that is of the upmost importance that the GPU is idle and 64 : : * all stray writes are flushed *before* we dismantle the backing 65 : : * storage for the pinned objects. 66 : : * 67 : : * However, since we are uncertain that resetting the GPU on older 68 : : * machines is a good idea, we don't - just in case it leaves the 69 : : * machine in an unusable condition. 70 : : */ 71 : : 72 : 0 : intel_gt_suspend_late(&i915->gt); 73 : : 74 : 0 : spin_lock_irqsave(&i915->mm.obj_lock, flags); 75 [ # # ]: 0 : for (phase = phases; *phase; phase++) { 76 : 0 : LIST_HEAD(keep); 77 : : 78 [ # # ]: 0 : while ((obj = first_mm_object(*phase))) { 79 : 0 : list_move_tail(&obj->mm.link, &keep); 80 : : 81 : : /* Beware the background _i915_gem_free_objects */ 82 [ # # ]: 0 : if (!kref_get_unless_zero(&obj->base.refcount)) 83 : 0 : continue; 84 : : 85 : 0 : spin_unlock_irqrestore(&i915->mm.obj_lock, flags); 86 : : 87 : 0 : i915_gem_object_lock(obj); 88 [ # # ]: 0 : WARN_ON(i915_gem_object_set_to_gtt_domain(obj, false)); 89 : 0 : i915_gem_object_unlock(obj); 90 : 0 : i915_gem_object_put(obj); 91 : : 92 [ # # ]: 0 : spin_lock_irqsave(&i915->mm.obj_lock, flags); 93 : : } 94 : : 95 [ # # ]: 0 : list_splice_tail(&keep, *phase); 96 : : } 97 : 0 : spin_unlock_irqrestore(&i915->mm.obj_lock, flags); 98 : 0 : } 99 : : 100 : 0 : void i915_gem_resume(struct drm_i915_private *i915) 101 : : { 102 : 0 : GEM_TRACE("%s\n", dev_name(i915->drm.dev)); 103 : : 104 : : /* 105 : : * As we didn't flush the kernel context before suspend, we cannot 106 : : * guarantee that the context image is complete. So let's just reset 107 : : * it and start again. 108 : : */ 109 : 0 : intel_gt_resume(&i915->gt); 110 : 0 : }