1 // SPDX-License-Identifier: MIT 2 /* 3 * Copyright © 2023 Intel Corporation 4 */ 5 6 #include <linux/dma-fence.h> 7 8 #include <drm/drm_crtc.h> 9 #include <drm/drm_vblank.h> 10 11 #include "i915_reg.h" 12 #include "intel_display_core.h" 13 #include "intel_display_irq.h" 14 #include "intel_display_rps.h" 15 #include "intel_display_types.h" 16 #include "intel_parent.h" 17 18 struct wait_rps_boost { 19 struct wait_queue_entry wait; 20 21 struct drm_crtc *crtc; 22 struct dma_fence *fence; 23 }; 24 25 static int do_rps_boost(struct wait_queue_entry *_wait, 26 unsigned mode, int sync, void *key) 27 { 28 struct wait_rps_boost *wait = container_of(_wait, typeof(*wait), wait); 29 struct intel_display *display = to_intel_display(wait->crtc->dev); 30 31 /* 32 * If we missed the vblank, but the request is already running it 33 * is reasonable to assume that it will complete before the next 34 * vblank without our intervention, so leave RPS alone if not started. 35 */ 36 intel_parent_rps_boost_if_not_started(display, wait->fence); 37 38 dma_fence_put(wait->fence); 39 40 drm_crtc_vblank_put(wait->crtc); 41 42 list_del(&wait->wait.entry); 43 kfree(wait); 44 return 1; 45 } 46 47 void intel_display_rps_boost_after_vblank(struct drm_crtc *crtc, 48 struct dma_fence *fence) 49 { 50 struct intel_display *display = to_intel_display(crtc->dev); 51 struct wait_rps_boost *wait; 52 53 if (!intel_parent_rps_available(display)) 54 return; 55 56 if (DISPLAY_VER(display) < 6) 57 return; 58 59 if (drm_crtc_vblank_get(crtc)) 60 return; 61 62 wait = kmalloc_obj(*wait); 63 if (!wait) { 64 drm_crtc_vblank_put(crtc); 65 return; 66 } 67 68 wait->fence = dma_fence_get(fence); 69 wait->crtc = crtc; 70 71 wait->wait.func = do_rps_boost; 72 wait->wait.flags = 0; 73 74 add_wait_queue(drm_crtc_vblank_waitqueue(crtc), &wait->wait); 75 } 76 77 void intel_display_rps_mark_interactive(struct intel_display *display, 78 struct intel_atomic_state *state, 79 bool interactive) 80 { 81 if (!intel_parent_rps_available(display)) 82 return; 83 84 if (state->rps_interactive == interactive) 85 return; 86 87 intel_parent_rps_mark_interactive(display, interactive); 88 89 state->rps_interactive = interactive; 90 } 91 92 void ilk_display_rps_enable(struct intel_display *display) 93 { 94 spin_lock(&display->irq.lock); 95 ilk_enable_display_irq(display, DE_PCU_EVENT); 96 spin_unlock(&display->irq.lock); 97 } 98 99 void ilk_display_rps_disable(struct intel_display *display) 100 { 101 spin_lock(&display->irq.lock); 102 ilk_disable_display_irq(display, DE_PCU_EVENT); 103 spin_unlock(&display->irq.lock); 104 } 105 106 void ilk_display_rps_irq_handler(struct intel_display *display) 107 { 108 intel_parent_rps_ilk_irq_handler(display); 109 } 110