Commit | Line | Data |
---|---|---|
05235c53 CW |
1 | /* |
2 | * Copyright © 2008-2015 Intel Corporation | |
3 | * | |
4 | * Permission is hereby granted, free of charge, to any person obtaining a | |
5 | * copy of this software and associated documentation files (the "Software"), | |
6 | * to deal in the Software without restriction, including without limitation | |
7 | * the rights to use, copy, modify, merge, publish, distribute, sublicense, | |
8 | * and/or sell copies of the Software, and to permit persons to whom the | |
9 | * Software is furnished to do so, subject to the following conditions: | |
10 | * | |
11 | * The above copyright notice and this permission notice (including the next | |
12 | * paragraph) shall be included in all copies or substantial portions of the | |
13 | * Software. | |
14 | * | |
15 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |
16 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |
17 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL | |
18 | * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |
19 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING | |
20 | * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS | |
21 | * IN THE SOFTWARE. | |
22 | * | |
23 | */ | |
24 | ||
25 | #ifndef I915_GEM_REQUEST_H | |
26 | #define I915_GEM_REQUEST_H | |
27 | ||
28 | /** | |
29 | * Request queue structure. | |
30 | * | |
31 | * The request queue allows us to note sequence numbers that have been emitted | |
32 | * and may be associated with active buffers to be retired. | |
33 | * | |
34 | * By keeping this list, we can avoid having to do questionable sequence | |
35 | * number comparisons on buffer last_read|write_seqno. It also allows an | |
36 | * emission time to be associated with the request for tracking how far ahead | |
37 | * of the GPU the submission is. | |
38 | * | |
39 | * The requests are reference counted, so upon creation they should have an | |
40 | * initial reference taken using kref_init | |
41 | */ | |
42 | struct drm_i915_gem_request { | |
43 | struct kref ref; | |
44 | ||
45 | /** On Which ring this request was generated */ | |
46 | struct drm_i915_private *i915; | |
47 | ||
48 | /** | |
49 | * Context and ring buffer related to this request | |
50 | * Contexts are refcounted, so when this request is associated with a | |
51 | * context, we must increment the context's refcount, to guarantee that | |
52 | * it persists while any request is linked to it. Requests themselves | |
53 | * are also refcounted, so the request will only be freed when the last | |
54 | * reference to it is dismissed, and the code in | |
55 | * i915_gem_request_free() will then decrement the refcount on the | |
56 | * context. | |
57 | */ | |
58 | struct i915_gem_context *ctx; | |
59 | struct intel_engine_cs *engine; | |
60 | struct intel_ringbuffer *ringbuf; | |
61 | struct intel_signal_node signaling; | |
62 | ||
63 | /** GEM sequence number associated with the previous request, | |
64 | * when the HWS breadcrumb is equal to this the GPU is processing | |
65 | * this request. | |
66 | */ | |
67 | u32 previous_seqno; | |
68 | ||
69 | /** GEM sequence number associated with this request, | |
70 | * when the HWS breadcrumb is equal or greater than this the GPU | |
71 | * has finished processing this request. | |
72 | */ | |
73 | u32 seqno; | |
74 | ||
75 | /** Position in the ringbuffer of the start of the request */ | |
76 | u32 head; | |
77 | ||
78 | /** | |
79 | * Position in the ringbuffer of the start of the postfix. | |
80 | * This is required to calculate the maximum available ringbuffer | |
81 | * space without overwriting the postfix. | |
82 | */ | |
83 | u32 postfix; | |
84 | ||
85 | /** Position in the ringbuffer of the end of the whole request */ | |
86 | u32 tail; | |
87 | ||
88 | /** Preallocate space in the ringbuffer for the emitting the request */ | |
89 | u32 reserved_space; | |
90 | ||
91 | /** | |
92 | * Context related to the previous request. | |
93 | * As the contexts are accessed by the hardware until the switch is | |
94 | * completed to a new context, the hardware may still be writing | |
95 | * to the context object after the breadcrumb is visible. We must | |
96 | * not unpin/unbind/prune that object whilst still active and so | |
97 | * we keep the previous context pinned until the following (this) | |
98 | * request is retired. | |
99 | */ | |
100 | struct i915_gem_context *previous_context; | |
101 | ||
102 | /** Batch buffer related to this request if any (used for | |
103 | * error state dump only). | |
104 | */ | |
105 | struct drm_i915_gem_object *batch_obj; | |
106 | ||
107 | /** Time at which this request was emitted, in jiffies. */ | |
108 | unsigned long emitted_jiffies; | |
109 | ||
110 | /** global list entry for this request */ | |
111 | struct list_head list; | |
112 | ||
113 | struct drm_i915_file_private *file_priv; | |
114 | /** file_priv list entry for this request */ | |
115 | struct list_head client_list; | |
116 | ||
117 | /** process identifier submitting this request */ | |
118 | struct pid *pid; | |
119 | ||
120 | /** | |
121 | * The ELSP only accepts two elements at a time, so we queue | |
122 | * context/tail pairs on a given queue (ring->execlist_queue) until the | |
123 | * hardware is available. The queue serves a double purpose: we also use | |
124 | * it to keep track of the up to 2 contexts currently in the hardware | |
125 | * (usually one in execution and the other queued up by the GPU): We | |
126 | * only remove elements from the head of the queue when the hardware | |
127 | * informs us that an element has been completed. | |
128 | * | |
129 | * All accesses to the queue are mediated by a spinlock | |
130 | * (ring->execlist_lock). | |
131 | */ | |
132 | ||
133 | /** Execlist link in the submission queue.*/ | |
134 | struct list_head execlist_link; | |
135 | ||
136 | /** Execlists no. of times this request has been sent to the ELSP */ | |
137 | int elsp_submitted; | |
138 | ||
139 | /** Execlists context hardware id. */ | |
140 | unsigned int ctx_hw_id; | |
141 | }; | |
142 | ||
143 | struct drm_i915_gem_request * __must_check | |
144 | i915_gem_request_alloc(struct intel_engine_cs *engine, | |
145 | struct i915_gem_context *ctx); | |
146 | void i915_gem_request_free(struct kref *req_ref); | |
147 | int i915_gem_request_add_to_client(struct drm_i915_gem_request *req, | |
148 | struct drm_file *file); | |
149 | void i915_gem_request_retire_upto(struct drm_i915_gem_request *req); | |
150 | ||
151 | static inline u32 | |
152 | i915_gem_request_get_seqno(struct drm_i915_gem_request *req) | |
153 | { | |
154 | return req ? req->seqno : 0; | |
155 | } | |
156 | ||
157 | static inline struct intel_engine_cs * | |
158 | i915_gem_request_get_engine(struct drm_i915_gem_request *req) | |
159 | { | |
160 | return req ? req->engine : NULL; | |
161 | } | |
162 | ||
163 | static inline struct drm_i915_gem_request * | |
164 | i915_gem_request_reference(struct drm_i915_gem_request *req) | |
165 | { | |
166 | if (req) | |
167 | kref_get(&req->ref); | |
168 | return req; | |
169 | } | |
170 | ||
171 | static inline void | |
172 | i915_gem_request_unreference(struct drm_i915_gem_request *req) | |
173 | { | |
174 | kref_put(&req->ref, i915_gem_request_free); | |
175 | } | |
176 | ||
177 | static inline void i915_gem_request_assign(struct drm_i915_gem_request **pdst, | |
178 | struct drm_i915_gem_request *src) | |
179 | { | |
180 | if (src) | |
181 | i915_gem_request_reference(src); | |
182 | ||
183 | if (*pdst) | |
184 | i915_gem_request_unreference(*pdst); | |
185 | ||
186 | *pdst = src; | |
187 | } | |
188 | ||
189 | void __i915_add_request(struct drm_i915_gem_request *req, | |
190 | struct drm_i915_gem_object *batch_obj, | |
191 | bool flush_caches); | |
192 | #define i915_add_request(req) \ | |
193 | __i915_add_request(req, NULL, true) | |
194 | #define i915_add_request_no_flush(req) \ | |
195 | __i915_add_request(req, NULL, false) | |
196 | ||
197 | struct intel_rps_client; | |
198 | ||
199 | int __i915_wait_request(struct drm_i915_gem_request *req, | |
200 | bool interruptible, | |
201 | s64 *timeout, | |
202 | struct intel_rps_client *rps); | |
203 | int __must_check i915_wait_request(struct drm_i915_gem_request *req); | |
204 | ||
205 | static inline u32 intel_engine_get_seqno(struct intel_engine_cs *engine); | |
206 | ||
207 | /** | |
208 | * Returns true if seq1 is later than seq2. | |
209 | */ | |
210 | static inline bool i915_seqno_passed(u32 seq1, u32 seq2) | |
211 | { | |
212 | return (s32)(seq1 - seq2) >= 0; | |
213 | } | |
214 | ||
215 | static inline bool | |
216 | i915_gem_request_started(const struct drm_i915_gem_request *req) | |
217 | { | |
218 | return i915_seqno_passed(intel_engine_get_seqno(req->engine), | |
219 | req->previous_seqno); | |
220 | } | |
221 | ||
222 | static inline bool | |
223 | i915_gem_request_completed(const struct drm_i915_gem_request *req) | |
224 | { | |
225 | return i915_seqno_passed(intel_engine_get_seqno(req->engine), | |
226 | req->seqno); | |
227 | } | |
228 | ||
229 | bool __i915_spin_request(const struct drm_i915_gem_request *request, | |
230 | int state, unsigned long timeout_us); | |
231 | static inline bool i915_spin_request(const struct drm_i915_gem_request *request, | |
232 | int state, unsigned long timeout_us) | |
233 | { | |
234 | return (i915_gem_request_started(request) && | |
235 | __i915_spin_request(request, state, timeout_us)); | |
236 | } | |
237 | ||
238 | #endif /* I915_GEM_REQUEST_H */ |