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