diff options
Diffstat (limited to 'drivers/gpu/nvgpu/gk20a/channel_gk20a.h')
-rw-r--r-- | drivers/gpu/nvgpu/gk20a/channel_gk20a.h | 431 |
1 files changed, 431 insertions, 0 deletions
diff --git a/drivers/gpu/nvgpu/gk20a/channel_gk20a.h b/drivers/gpu/nvgpu/gk20a/channel_gk20a.h new file mode 100644 index 00000000..d865849b --- /dev/null +++ b/drivers/gpu/nvgpu/gk20a/channel_gk20a.h | |||
@@ -0,0 +1,431 @@ | |||
1 | /* | ||
2 | * GK20A graphics channel | ||
3 | * | ||
4 | * Copyright (c) 2011-2017, NVIDIA CORPORATION. All rights reserved. | ||
5 | * | ||
6 | * Permission is hereby granted, free of charge, to any person obtaining a | ||
7 | * copy of this software and associated documentation files (the "Software"), | ||
8 | * to deal in the Software without restriction, including without limitation | ||
9 | * the rights to use, copy, modify, merge, publish, distribute, sublicense, | ||
10 | * and/or sell copies of the Software, and to permit persons to whom the | ||
11 | * Software is furnished to do so, subject to the following conditions: | ||
12 | * | ||
13 | * The above copyright notice and this permission notice shall be included in | ||
14 | * all copies or substantial portions of the Software. | ||
15 | * | ||
16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL | ||
19 | * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING | ||
21 | * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER | ||
22 | * DEALINGS IN THE SOFTWARE. | ||
23 | */ | ||
24 | #ifndef CHANNEL_GK20A_H | ||
25 | #define CHANNEL_GK20A_H | ||
26 | |||
27 | /* TODO: To be removed when work_struct update_fn_work is moved out of common code */ | ||
28 | #include <linux/workqueue.h> | ||
29 | |||
30 | #include <nvgpu/list.h> | ||
31 | #include <nvgpu/lock.h> | ||
32 | #include <nvgpu/timers.h> | ||
33 | #include <nvgpu/cond.h> | ||
34 | #include <nvgpu/atomic.h> | ||
35 | |||
36 | struct gk20a; | ||
37 | struct gr_gk20a; | ||
38 | struct dbg_session_gk20a; | ||
39 | struct gk20a_fence; | ||
40 | struct fifo_profile_gk20a; | ||
41 | |||
42 | #include "channel_sync_gk20a.h" | ||
43 | |||
44 | #include "mm_gk20a.h" | ||
45 | #include "gr_gk20a.h" | ||
46 | #include "fence_gk20a.h" | ||
47 | #ifdef CONFIG_TEGRA_19x_GPU | ||
48 | #include "channel_t19x.h" | ||
49 | #endif | ||
50 | |||
51 | /* Flags to be passed to gk20a_channel_alloc_gpfifo() */ | ||
52 | #define NVGPU_GPFIFO_FLAGS_SUPPORT_VPR (1 << 0) | ||
53 | #define NVGPU_GPFIFO_FLAGS_SUPPORT_DETERMINISTIC (1 << 1) | ||
54 | |||
55 | /* Flags to be passed to g->ops.gr.alloc_obj_ctx() */ | ||
56 | #define NVGPU_OBJ_CTX_FLAGS_SUPPORT_GFXP (1 << 1) | ||
57 | #define NVGPU_OBJ_CTX_FLAGS_SUPPORT_CILP (1 << 2) | ||
58 | |||
59 | struct notification { | ||
60 | struct { | ||
61 | u32 nanoseconds[2]; | ||
62 | } timestamp; | ||
63 | u32 info32; | ||
64 | u16 info16; | ||
65 | u16 status; | ||
66 | }; | ||
67 | |||
68 | /* contexts associated with a channel */ | ||
69 | struct channel_ctx_gk20a { | ||
70 | struct gr_ctx_desc *gr_ctx; | ||
71 | struct patch_desc patch_ctx; | ||
72 | struct zcull_ctx_desc zcull_ctx; | ||
73 | struct pm_ctx_desc pm_ctx; | ||
74 | u64 global_ctx_buffer_va[NR_GLOBAL_CTX_BUF_VA]; | ||
75 | u64 global_ctx_buffer_size[NR_GLOBAL_CTX_BUF_VA]; | ||
76 | int global_ctx_buffer_index[NR_GLOBAL_CTX_BUF_VA]; | ||
77 | bool global_ctx_buffer_mapped; | ||
78 | struct ctx_header_desc ctx_header; | ||
79 | }; | ||
80 | |||
81 | struct channel_gk20a_job { | ||
82 | struct nvgpu_mapped_buf **mapped_buffers; | ||
83 | int num_mapped_buffers; | ||
84 | struct gk20a_fence *pre_fence; | ||
85 | struct gk20a_fence *post_fence; | ||
86 | struct priv_cmd_entry *wait_cmd; | ||
87 | struct priv_cmd_entry *incr_cmd; | ||
88 | struct nvgpu_list_node list; | ||
89 | }; | ||
90 | |||
91 | static inline struct channel_gk20a_job * | ||
92 | channel_gk20a_job_from_list(struct nvgpu_list_node *node) | ||
93 | { | ||
94 | return (struct channel_gk20a_job *) | ||
95 | ((uintptr_t)node - offsetof(struct channel_gk20a_job, list)); | ||
96 | }; | ||
97 | |||
98 | struct channel_gk20a_joblist { | ||
99 | struct { | ||
100 | bool enabled; | ||
101 | unsigned int length; | ||
102 | unsigned int put; | ||
103 | unsigned int get; | ||
104 | struct channel_gk20a_job *jobs; | ||
105 | struct nvgpu_mutex read_lock; | ||
106 | } pre_alloc; | ||
107 | |||
108 | struct { | ||
109 | struct nvgpu_list_node jobs; | ||
110 | struct nvgpu_spinlock lock; | ||
111 | } dynamic; | ||
112 | |||
113 | /* | ||
114 | * Synchronize abort cleanup (when closing a channel) and job cleanup | ||
115 | * (asynchronously from worker) - protect from concurrent access when | ||
116 | * job resources are being freed. | ||
117 | */ | ||
118 | struct nvgpu_mutex cleanup_lock; | ||
119 | }; | ||
120 | |||
121 | struct channel_gk20a_timeout { | ||
122 | struct nvgpu_raw_spinlock lock; | ||
123 | struct nvgpu_timeout timer; | ||
124 | bool running; | ||
125 | u32 gp_get; | ||
126 | u64 pb_get; | ||
127 | }; | ||
128 | |||
129 | struct gk20a_event_id_data { | ||
130 | struct gk20a *g; | ||
131 | |||
132 | int id; /* ch or tsg */ | ||
133 | bool is_tsg; | ||
134 | u32 event_id; | ||
135 | |||
136 | bool event_posted; | ||
137 | |||
138 | struct nvgpu_cond event_id_wq; | ||
139 | struct nvgpu_mutex lock; | ||
140 | struct nvgpu_list_node event_id_node; | ||
141 | }; | ||
142 | |||
143 | static inline struct gk20a_event_id_data * | ||
144 | gk20a_event_id_data_from_event_id_node(struct nvgpu_list_node *node) | ||
145 | { | ||
146 | return (struct gk20a_event_id_data *) | ||
147 | ((uintptr_t)node - offsetof(struct gk20a_event_id_data, event_id_node)); | ||
148 | }; | ||
149 | |||
150 | /* | ||
151 | * Track refcount actions, saving their stack traces. This number specifies how | ||
152 | * many most recent actions are stored in a buffer. Set to 0 to disable. 128 | ||
153 | * should be enough to track moderately hard problems from the start. | ||
154 | */ | ||
155 | #define GK20A_CHANNEL_REFCOUNT_TRACKING 0 | ||
156 | /* Stack depth for the saved actions. */ | ||
157 | #define GK20A_CHANNEL_REFCOUNT_TRACKING_STACKLEN 8 | ||
158 | |||
159 | /* | ||
160 | * Because the puts and gets are not linked together explicitly (although they | ||
161 | * should always come in pairs), it's not possible to tell which ref holder to | ||
162 | * delete from the list when doing a put. So, just store some number of most | ||
163 | * recent gets and puts in a ring buffer, to obtain a history. | ||
164 | * | ||
165 | * These are zeroed when a channel is closed, so a new one starts fresh. | ||
166 | */ | ||
167 | |||
168 | enum channel_gk20a_ref_action_type { | ||
169 | channel_gk20a_ref_action_get, | ||
170 | channel_gk20a_ref_action_put | ||
171 | }; | ||
172 | |||
173 | #if GK20A_CHANNEL_REFCOUNT_TRACKING | ||
174 | |||
175 | #include <linux/stacktrace.h> | ||
176 | |||
177 | struct channel_gk20a_ref_action { | ||
178 | enum channel_gk20a_ref_action_type type; | ||
179 | s64 timestamp_ms; | ||
180 | /* | ||
181 | * Many of these traces will be similar. Simpler to just capture | ||
182 | * duplicates than to have a separate database for the entries. | ||
183 | */ | ||
184 | struct stack_trace trace; | ||
185 | unsigned long trace_entries[GK20A_CHANNEL_REFCOUNT_TRACKING_STACKLEN]; | ||
186 | }; | ||
187 | #endif | ||
188 | |||
189 | /* this is the priv element of struct nvhost_channel */ | ||
190 | struct channel_gk20a { | ||
191 | struct gk20a *g; /* set only when channel is active */ | ||
192 | |||
193 | struct nvgpu_list_node free_chs; | ||
194 | |||
195 | struct nvgpu_spinlock ref_obtain_lock; | ||
196 | bool referenceable; | ||
197 | nvgpu_atomic_t ref_count; | ||
198 | struct nvgpu_cond ref_count_dec_wq; | ||
199 | #if GK20A_CHANNEL_REFCOUNT_TRACKING | ||
200 | /* | ||
201 | * Ring buffer for most recent refcount gets and puts. Protected by | ||
202 | * ref_actions_lock when getting or putting refs (i.e., adding | ||
203 | * entries), and when reading entries. | ||
204 | */ | ||
205 | struct channel_gk20a_ref_action ref_actions[ | ||
206 | GK20A_CHANNEL_REFCOUNT_TRACKING]; | ||
207 | size_t ref_actions_put; /* index of next write */ | ||
208 | struct nvgpu_spinlock ref_actions_lock; | ||
209 | #endif | ||
210 | |||
211 | struct nvgpu_semaphore_int *hw_sema; | ||
212 | |||
213 | int chid; | ||
214 | bool wdt_enabled; | ||
215 | nvgpu_atomic_t bound; | ||
216 | bool first_init; | ||
217 | bool vpr; | ||
218 | bool deterministic; | ||
219 | /* deterministic, but explicitly idle and submits disallowed */ | ||
220 | bool deterministic_railgate_allowed; | ||
221 | bool cde; | ||
222 | pid_t pid; | ||
223 | pid_t tgid; | ||
224 | struct nvgpu_mutex ioctl_lock; | ||
225 | |||
226 | int tsgid; | ||
227 | struct nvgpu_list_node ch_entry; /* channel's entry in TSG */ | ||
228 | |||
229 | struct channel_gk20a_joblist joblist; | ||
230 | struct nvgpu_allocator fence_allocator; | ||
231 | |||
232 | struct vm_gk20a *vm; | ||
233 | |||
234 | struct gpfifo_desc gpfifo; | ||
235 | |||
236 | struct channel_ctx_gk20a ch_ctx; | ||
237 | |||
238 | struct nvgpu_mem inst_block; | ||
239 | |||
240 | u64 userd_iova; | ||
241 | u64 userd_gpu_va; | ||
242 | |||
243 | u32 obj_class; /* we support only one obj per channel */ | ||
244 | |||
245 | struct priv_cmd_queue priv_cmd_q; | ||
246 | |||
247 | struct nvgpu_cond notifier_wq; | ||
248 | struct nvgpu_cond semaphore_wq; | ||
249 | |||
250 | u32 timeout_accumulated_ms; | ||
251 | u32 timeout_gpfifo_get; | ||
252 | |||
253 | struct channel_gk20a_timeout timeout; | ||
254 | /* for job cleanup handling in the background worker */ | ||
255 | struct nvgpu_list_node worker_item; | ||
256 | |||
257 | #if defined(CONFIG_GK20A_CYCLE_STATS) | ||
258 | struct { | ||
259 | void *cyclestate_buffer; | ||
260 | u32 cyclestate_buffer_size; | ||
261 | struct dma_buf *cyclestate_buffer_handler; | ||
262 | struct nvgpu_mutex cyclestate_buffer_mutex; | ||
263 | } cyclestate; | ||
264 | |||
265 | struct nvgpu_mutex cs_client_mutex; | ||
266 | struct gk20a_cs_snapshot_client *cs_client; | ||
267 | #endif | ||
268 | struct nvgpu_mutex dbg_s_lock; | ||
269 | struct nvgpu_list_node dbg_s_list; | ||
270 | |||
271 | struct nvgpu_list_node event_id_list; | ||
272 | struct nvgpu_mutex event_id_list_lock; | ||
273 | |||
274 | bool has_timedout; | ||
275 | u32 timeout_ms_max; | ||
276 | bool timeout_debug_dump; | ||
277 | unsigned int timeslice_us; | ||
278 | |||
279 | struct dma_buf *error_notifier_ref; | ||
280 | struct nvgpu_notification *error_notifier; | ||
281 | void *error_notifier_va; | ||
282 | struct nvgpu_mutex error_notifier_mutex; | ||
283 | |||
284 | struct nvgpu_mutex sync_lock; | ||
285 | struct gk20a_channel_sync *sync; | ||
286 | |||
287 | #ifdef CONFIG_TEGRA_GR_VIRTUALIZATION | ||
288 | u64 virt_ctx; | ||
289 | #endif | ||
290 | |||
291 | /* | ||
292 | * Signal channel owner via a callback, if set, in job cleanup with | ||
293 | * schedule_work. Means that something finished on the channel (perhaps | ||
294 | * more than one job). | ||
295 | */ | ||
296 | void (*update_fn)(struct channel_gk20a *, void *); | ||
297 | void *update_fn_data; | ||
298 | struct nvgpu_spinlock update_fn_lock; /* make access to the two above atomic */ | ||
299 | struct work_struct update_fn_work; | ||
300 | |||
301 | u32 interleave_level; | ||
302 | |||
303 | u32 runlist_id; | ||
304 | |||
305 | bool is_privileged_channel; | ||
306 | #ifdef CONFIG_TEGRA_19x_GPU | ||
307 | struct channel_t19x t19x; | ||
308 | #endif | ||
309 | }; | ||
310 | |||
311 | static inline struct channel_gk20a * | ||
312 | channel_gk20a_from_free_chs(struct nvgpu_list_node *node) | ||
313 | { | ||
314 | return (struct channel_gk20a *) | ||
315 | ((uintptr_t)node - offsetof(struct channel_gk20a, free_chs)); | ||
316 | }; | ||
317 | |||
318 | static inline struct channel_gk20a * | ||
319 | channel_gk20a_from_ch_entry(struct nvgpu_list_node *node) | ||
320 | { | ||
321 | return (struct channel_gk20a *) | ||
322 | ((uintptr_t)node - offsetof(struct channel_gk20a, ch_entry)); | ||
323 | }; | ||
324 | |||
325 | static inline struct channel_gk20a * | ||
326 | channel_gk20a_from_worker_item(struct nvgpu_list_node *node) | ||
327 | { | ||
328 | return (struct channel_gk20a *) | ||
329 | ((uintptr_t)node - offsetof(struct channel_gk20a, worker_item)); | ||
330 | }; | ||
331 | |||
332 | static inline bool gk20a_channel_as_bound(struct channel_gk20a *ch) | ||
333 | { | ||
334 | return !!ch->vm; | ||
335 | } | ||
336 | int channel_gk20a_commit_va(struct channel_gk20a *c); | ||
337 | int gk20a_init_channel_support(struct gk20a *, u32 chid); | ||
338 | |||
339 | /* must be inside gk20a_busy()..gk20a_idle() */ | ||
340 | void gk20a_channel_close(struct channel_gk20a *ch); | ||
341 | void __gk20a_channel_kill(struct channel_gk20a *ch); | ||
342 | |||
343 | bool gk20a_channel_update_and_check_timeout(struct channel_gk20a *ch, | ||
344 | u32 timeout_delta_ms, bool *progress); | ||
345 | void gk20a_disable_channel(struct channel_gk20a *ch); | ||
346 | void gk20a_channel_abort(struct channel_gk20a *ch, bool channel_preempt); | ||
347 | void gk20a_channel_abort_clean_up(struct channel_gk20a *ch); | ||
348 | void gk20a_set_error_notifier(struct channel_gk20a *ch, __u32 error); | ||
349 | void gk20a_set_error_notifier_locked(struct channel_gk20a *ch, __u32 error); | ||
350 | void gk20a_channel_semaphore_wakeup(struct gk20a *g, bool post_events); | ||
351 | int gk20a_channel_alloc_priv_cmdbuf(struct channel_gk20a *c, u32 size, | ||
352 | struct priv_cmd_entry *entry); | ||
353 | int gk20a_free_priv_cmdbuf(struct channel_gk20a *c, struct priv_cmd_entry *e); | ||
354 | |||
355 | int gk20a_enable_channel_tsg(struct gk20a *g, struct channel_gk20a *ch); | ||
356 | int gk20a_disable_channel_tsg(struct gk20a *g, struct channel_gk20a *ch); | ||
357 | |||
358 | int gk20a_channel_suspend(struct gk20a *g); | ||
359 | int gk20a_channel_resume(struct gk20a *g); | ||
360 | |||
361 | void gk20a_channel_deterministic_idle(struct gk20a *g); | ||
362 | void gk20a_channel_deterministic_unidle(struct gk20a *g); | ||
363 | |||
364 | int nvgpu_channel_worker_init(struct gk20a *g); | ||
365 | void nvgpu_channel_worker_deinit(struct gk20a *g); | ||
366 | |||
367 | struct channel_gk20a *gk20a_get_channel_from_file(int fd); | ||
368 | void gk20a_channel_update(struct channel_gk20a *c); | ||
369 | |||
370 | /* returns ch if reference was obtained */ | ||
371 | struct channel_gk20a *__must_check _gk20a_channel_get(struct channel_gk20a *ch, | ||
372 | const char *caller); | ||
373 | #define gk20a_channel_get(ch) _gk20a_channel_get(ch, __func__) | ||
374 | |||
375 | |||
376 | void _gk20a_channel_put(struct channel_gk20a *ch, const char *caller); | ||
377 | #define gk20a_channel_put(ch) _gk20a_channel_put(ch, __func__) | ||
378 | |||
379 | int gk20a_wait_channel_idle(struct channel_gk20a *ch); | ||
380 | |||
381 | /* runlist_id -1 is synonym for ENGINE_GR_GK20A runlist id */ | ||
382 | struct channel_gk20a *gk20a_open_new_channel(struct gk20a *g, | ||
383 | s32 runlist_id, | ||
384 | bool is_privileged_channel); | ||
385 | struct channel_gk20a *gk20a_open_new_channel_with_cb(struct gk20a *g, | ||
386 | void (*update_fn)(struct channel_gk20a *, void *), | ||
387 | void *update_fn_data, | ||
388 | int runlist_id, | ||
389 | bool is_privileged_channel); | ||
390 | |||
391 | int gk20a_channel_alloc_gpfifo(struct channel_gk20a *c, | ||
392 | unsigned int num_entries, | ||
393 | unsigned int num_inflight_jobs, | ||
394 | u32 flags); | ||
395 | void gk20a_channel_free_cycle_stats_buffer(struct channel_gk20a *ch); | ||
396 | int gk20a_channel_free_cycle_stats_snapshot(struct channel_gk20a *ch); | ||
397 | |||
398 | void gk20a_channel_timeout_restart_all_channels(struct gk20a *g); | ||
399 | |||
400 | bool channel_gk20a_is_prealloc_enabled(struct channel_gk20a *c); | ||
401 | void channel_gk20a_joblist_lock(struct channel_gk20a *c); | ||
402 | void channel_gk20a_joblist_unlock(struct channel_gk20a *c); | ||
403 | bool channel_gk20a_joblist_is_empty(struct channel_gk20a *c); | ||
404 | |||
405 | int channel_gk20a_update_runlist(struct channel_gk20a *c, bool add); | ||
406 | u32 gk20a_channel_get_timeslice(struct channel_gk20a *ch); | ||
407 | int gk20a_channel_get_timescale_from_timeslice(struct gk20a *g, | ||
408 | int timeslice_period, | ||
409 | int *__timeslice_timeout, int *__timeslice_scale); | ||
410 | int gk20a_channel_set_runlist_interleave(struct channel_gk20a *ch, | ||
411 | u32 level); | ||
412 | void gk20a_channel_event_id_post_event(struct channel_gk20a *ch, | ||
413 | u32 event_id); | ||
414 | |||
415 | int channel_gk20a_alloc_job(struct channel_gk20a *c, | ||
416 | struct channel_gk20a_job **job_out); | ||
417 | void channel_gk20a_free_job(struct channel_gk20a *c, | ||
418 | struct channel_gk20a_job *job); | ||
419 | u32 nvgpu_get_gp_free_count(struct channel_gk20a *c); | ||
420 | u32 nvgpu_gp_free_count(struct channel_gk20a *c); | ||
421 | int gk20a_channel_add_job(struct channel_gk20a *c, | ||
422 | struct channel_gk20a_job *job, | ||
423 | bool skip_buffer_refcounting); | ||
424 | void free_priv_cmdbuf(struct channel_gk20a *c, | ||
425 | struct priv_cmd_entry *e); | ||
426 | void gk20a_channel_clean_up_jobs(struct channel_gk20a *c, | ||
427 | bool clean_all); | ||
428 | |||
429 | u32 nvgpu_get_gpfifo_entry_size(void); | ||
430 | |||
431 | #endif /* CHANNEL_GK20A_H */ | ||