summaryrefslogtreecommitdiffstats
path: root/drivers/gpu/nvgpu/gk20a/tsg_gk20a.c
diff options
context:
space:
mode:
authorKonsta Holtta <kholtta@nvidia.com>2018-09-12 05:40:10 -0400
committermobile promotions <svcmobile_promotions@nvidia.com>2018-09-24 18:53:48 -0400
commitc47eab005ad9a26a36d2c7ca1595c790ff1bc40d (patch)
treebfaa8f27f141a98478b664ba8b2ae5ba788546a6 /drivers/gpu/nvgpu/gk20a/tsg_gk20a.c
parent5c7a740403fe5b65149b8b30d1007fd02b33c890 (diff)
gpu: nvgpu: move tsg code to common
tsg_gk20a.c doesn't depend on any specific hardware, so move it to the common directory. Rename the posix tsg file to posix-tsg.c. Jira NVGPU-967 Change-Id: I6e8908a8f6cf43132db8dffe3a99e424e4f764b1 Signed-off-by: Konsta Holtta <kholtta@nvidia.com> Reviewed-on: https://git-master.nvidia.com/r/1821509 Reviewed-by: mobile promotions <svcmobile_promotions@nvidia.com> Tested-by: mobile promotions <svcmobile_promotions@nvidia.com>
Diffstat (limited to 'drivers/gpu/nvgpu/gk20a/tsg_gk20a.c')
-rw-r--r--drivers/gpu/nvgpu/gk20a/tsg_gk20a.c442
1 files changed, 0 insertions, 442 deletions
diff --git a/drivers/gpu/nvgpu/gk20a/tsg_gk20a.c b/drivers/gpu/nvgpu/gk20a/tsg_gk20a.c
deleted file mode 100644
index 885ce172..00000000
--- a/drivers/gpu/nvgpu/gk20a/tsg_gk20a.c
+++ /dev/null
@@ -1,442 +0,0 @@
1/*
2 * Copyright (c) 2014-2018, NVIDIA CORPORATION. All rights reserved.
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 shall be included in
12 * all copies or substantial portions of the Software.
13 *
14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
17 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
19 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
20 * DEALINGS IN THE SOFTWARE.
21 */
22
23#include <nvgpu/kmem.h>
24#include <nvgpu/log.h>
25#include <nvgpu/os_sched.h>
26#include <nvgpu/channel.h>
27
28#include "gk20a.h"
29#include "tsg_gk20a.h"
30
31bool gk20a_is_channel_marked_as_tsg(struct channel_gk20a *ch)
32{
33 return !(ch->tsgid == NVGPU_INVALID_TSG_ID);
34}
35
36int gk20a_enable_tsg(struct tsg_gk20a *tsg)
37{
38 struct gk20a *g = tsg->g;
39 struct channel_gk20a *ch;
40 bool is_next, is_ctx_reload;
41
42 gk20a_fifo_disable_tsg_sched(g, tsg);
43
44 /*
45 * Due to h/w bug that exists in Maxwell and Pascal,
46 * we first need to enable all channels with NEXT and CTX_RELOAD set,
47 * and then rest of the channels should be enabled
48 */
49 nvgpu_rwsem_down_read(&tsg->ch_list_lock);
50 nvgpu_list_for_each_entry(ch, &tsg->ch_list, channel_gk20a, ch_entry) {
51 is_next = gk20a_fifo_channel_status_is_next(g, ch->chid);
52 is_ctx_reload = gk20a_fifo_channel_status_is_ctx_reload(g, ch->chid);
53
54 if (is_next || is_ctx_reload) {
55 g->ops.fifo.enable_channel(ch);
56 }
57 }
58
59 nvgpu_list_for_each_entry(ch, &tsg->ch_list, channel_gk20a, ch_entry) {
60 is_next = gk20a_fifo_channel_status_is_next(g, ch->chid);
61 is_ctx_reload = gk20a_fifo_channel_status_is_ctx_reload(g, ch->chid);
62
63 if (is_next || is_ctx_reload) {
64 continue;
65 }
66
67 g->ops.fifo.enable_channel(ch);
68 }
69 nvgpu_rwsem_up_read(&tsg->ch_list_lock);
70
71 gk20a_fifo_enable_tsg_sched(g, tsg);
72
73 return 0;
74}
75
76int gk20a_disable_tsg(struct tsg_gk20a *tsg)
77{
78 struct gk20a *g = tsg->g;
79 struct channel_gk20a *ch;
80
81 nvgpu_rwsem_down_read(&tsg->ch_list_lock);
82 nvgpu_list_for_each_entry(ch, &tsg->ch_list, channel_gk20a, ch_entry) {
83 g->ops.fifo.disable_channel(ch);
84 }
85 nvgpu_rwsem_up_read(&tsg->ch_list_lock);
86
87 return 0;
88}
89
90static bool gk20a_is_channel_active(struct gk20a *g, struct channel_gk20a *ch)
91{
92 struct fifo_gk20a *f = &g->fifo;
93 struct fifo_runlist_info_gk20a *runlist;
94 unsigned int i;
95
96 for (i = 0; i < f->max_runlists; ++i) {
97 runlist = &f->runlist_info[i];
98 if (test_bit(ch->chid, runlist->active_channels)) {
99 return true;
100 }
101 }
102
103 return false;
104}
105
106/*
107 * API to mark channel as part of TSG
108 *
109 * Note that channel is not runnable when we bind it to TSG
110 */
111int gk20a_tsg_bind_channel(struct tsg_gk20a *tsg,
112 struct channel_gk20a *ch)
113{
114 struct gk20a *g = ch->g;
115
116 nvgpu_log_fn(g, " ");
117
118 /* check if channel is already bound to some TSG */
119 if (gk20a_is_channel_marked_as_tsg(ch)) {
120 return -EINVAL;
121 }
122
123 /* channel cannot be bound to TSG if it is already active */
124 if (gk20a_is_channel_active(tsg->g, ch)) {
125 return -EINVAL;
126 }
127
128 ch->tsgid = tsg->tsgid;
129
130 /* all the channel part of TSG should need to be same runlist_id */
131 if (tsg->runlist_id == FIFO_INVAL_TSG_ID) {
132 tsg->runlist_id = ch->runlist_id;
133 } else if (tsg->runlist_id != ch->runlist_id) {
134 nvgpu_err(tsg->g,
135 "Error: TSG channel should be share same runlist ch[%d] tsg[%d]",
136 ch->runlist_id, tsg->runlist_id);
137 return -EINVAL;
138 }
139
140 nvgpu_rwsem_down_write(&tsg->ch_list_lock);
141 nvgpu_list_add_tail(&ch->ch_entry, &tsg->ch_list);
142 nvgpu_rwsem_up_write(&tsg->ch_list_lock);
143
144 nvgpu_ref_get(&tsg->refcount);
145
146 nvgpu_log(g, gpu_dbg_fn, "BIND tsg:%d channel:%d\n",
147 tsg->tsgid, ch->chid);
148
149 nvgpu_log_fn(g, "done");
150 return 0;
151}
152
153int gk20a_tsg_unbind_channel(struct channel_gk20a *ch)
154{
155 struct gk20a *g = ch->g;
156 struct tsg_gk20a *tsg = &g->fifo.tsg[ch->tsgid];
157 int err;
158
159 err = g->ops.fifo.tsg_unbind_channel(ch);
160 if (err) {
161 nvgpu_err(g, "Channel %d unbind failed, tearing down TSG %d",
162 ch->chid, tsg->tsgid);
163
164 gk20a_fifo_abort_tsg(ch->g, ch->tsgid, true);
165 /* If channel unbind fails, channel is still part of runlist */
166 channel_gk20a_update_runlist(ch, false);
167
168 nvgpu_rwsem_down_write(&tsg->ch_list_lock);
169 nvgpu_list_del(&ch->ch_entry);
170 nvgpu_rwsem_up_write(&tsg->ch_list_lock);
171 }
172
173 nvgpu_ref_put(&tsg->refcount, gk20a_tsg_release);
174 ch->tsgid = NVGPU_INVALID_TSG_ID;
175
176 nvgpu_log(g, gpu_dbg_fn, "UNBIND tsg:%d channel:%d\n",
177 tsg->tsgid, ch->chid);
178
179 return 0;
180}
181
182int gk20a_init_tsg_support(struct gk20a *g, u32 tsgid)
183{
184 struct tsg_gk20a *tsg = NULL;
185 int err;
186
187 if (tsgid >= g->fifo.num_channels) {
188 return -EINVAL;
189 }
190
191 tsg = &g->fifo.tsg[tsgid];
192
193 tsg->in_use = false;
194 tsg->tsgid = tsgid;
195
196 nvgpu_init_list_node(&tsg->ch_list);
197 nvgpu_rwsem_init(&tsg->ch_list_lock);
198
199 nvgpu_init_list_node(&tsg->event_id_list);
200 err = nvgpu_mutex_init(&tsg->event_id_list_lock);
201 if (err) {
202 tsg->in_use = true; /* make this TSG unusable */
203 return err;
204 }
205
206 return 0;
207}
208
209int gk20a_tsg_set_runlist_interleave(struct tsg_gk20a *tsg, u32 level)
210{
211 struct gk20a *g = tsg->g;
212 int ret;
213
214 nvgpu_log(g, gpu_dbg_sched, "tsgid=%u interleave=%u", tsg->tsgid, level);
215
216 switch (level) {
217 case NVGPU_FIFO_RUNLIST_INTERLEAVE_LEVEL_LOW:
218 case NVGPU_FIFO_RUNLIST_INTERLEAVE_LEVEL_MEDIUM:
219 case NVGPU_FIFO_RUNLIST_INTERLEAVE_LEVEL_HIGH:
220 ret = g->ops.fifo.set_runlist_interleave(g, tsg->tsgid,
221 0, level);
222 if (!ret) {
223 tsg->interleave_level = level;
224 }
225 break;
226 default:
227 ret = -EINVAL;
228 break;
229 }
230
231 return ret ? ret : g->ops.fifo.update_runlist(g, tsg->runlist_id, ~0, true, true);
232}
233
234int gk20a_tsg_set_timeslice(struct tsg_gk20a *tsg, u32 timeslice)
235{
236 struct gk20a *g = tsg->g;
237
238 nvgpu_log(g, gpu_dbg_sched, "tsgid=%u timeslice=%u us", tsg->tsgid, timeslice);
239
240 return g->ops.fifo.tsg_set_timeslice(tsg, timeslice);
241}
242
243u32 gk20a_tsg_get_timeslice(struct tsg_gk20a *tsg)
244{
245 struct gk20a *g = tsg->g;
246
247 if (!tsg->timeslice_us) {
248 return g->ops.fifo.default_timeslice_us(g);
249 }
250
251 return tsg->timeslice_us;
252}
253
254static void release_used_tsg(struct fifo_gk20a *f, struct tsg_gk20a *tsg)
255{
256 nvgpu_mutex_acquire(&f->tsg_inuse_mutex);
257 f->tsg[tsg->tsgid].in_use = false;
258 nvgpu_mutex_release(&f->tsg_inuse_mutex);
259}
260
261static struct tsg_gk20a *gk20a_tsg_acquire_unused_tsg(struct fifo_gk20a *f)
262{
263 struct tsg_gk20a *tsg = NULL;
264 unsigned int tsgid;
265
266 nvgpu_mutex_acquire(&f->tsg_inuse_mutex);
267 for (tsgid = 0; tsgid < f->num_channels; tsgid++) {
268 if (!f->tsg[tsgid].in_use) {
269 f->tsg[tsgid].in_use = true;
270 tsg = &f->tsg[tsgid];
271 break;
272 }
273 }
274 nvgpu_mutex_release(&f->tsg_inuse_mutex);
275
276 return tsg;
277}
278
279struct tsg_gk20a *gk20a_tsg_open(struct gk20a *g, pid_t pid)
280{
281 struct tsg_gk20a *tsg;
282 int err;
283
284 tsg = gk20a_tsg_acquire_unused_tsg(&g->fifo);
285 if (tsg == NULL) {
286 return NULL;
287 }
288
289 /* we need to allocate this after g->ops.gr.init_fs_state() since
290 * we initialize gr->no_of_sm in this function
291 */
292 if (g->gr.no_of_sm == 0U) {
293 nvgpu_err(g, "no_of_sm %d not set, failed allocation",
294 g->gr.no_of_sm);
295 return NULL;
296 }
297
298 err = gk20a_tsg_alloc_sm_error_states_mem(g, tsg, g->gr.no_of_sm);
299 if (err != 0) {
300 return NULL;
301 }
302
303 tsg->g = g;
304 tsg->num_active_channels = 0;
305 nvgpu_ref_init(&tsg->refcount);
306
307 tsg->vm = NULL;
308 tsg->interleave_level = NVGPU_FIFO_RUNLIST_INTERLEAVE_LEVEL_LOW;
309 tsg->timeslice_us = 0;
310 tsg->timeslice_timeout = 0;
311 tsg->timeslice_scale = 0;
312 tsg->runlist_id = ~0;
313 tsg->tgid = pid;
314 tsg->sm_exception_mask_type = NVGPU_SM_EXCEPTION_TYPE_MASK_NONE;
315
316 if (g->ops.fifo.init_eng_method_buffers) {
317 g->ops.fifo.init_eng_method_buffers(g, tsg);
318 }
319
320 if (g->ops.fifo.tsg_open) {
321 err = g->ops.fifo.tsg_open(tsg);
322 if (err != 0) {
323 nvgpu_err(g, "tsg %d fifo open failed %d",
324 tsg->tsgid, err);
325 goto clean_up;
326 }
327 }
328
329 nvgpu_log(g, gpu_dbg_fn, "tsg opened %d\n", tsg->tsgid);
330
331 return tsg;
332
333clean_up:
334
335 if(tsg->sm_error_states != NULL) {
336 nvgpu_kfree(g, tsg->sm_error_states);
337 tsg->sm_error_states = NULL;
338 }
339
340 nvgpu_ref_put(&tsg->refcount, gk20a_tsg_release);
341 return NULL;
342}
343
344void gk20a_tsg_release(struct nvgpu_ref *ref)
345{
346 struct tsg_gk20a *tsg = container_of(ref, struct tsg_gk20a, refcount);
347 struct gk20a *g = tsg->g;
348 struct gk20a_event_id_data *event_id_data, *event_id_data_temp;
349
350 if (g->ops.fifo.tsg_release != NULL) {
351 g->ops.fifo.tsg_release(tsg);
352 }
353
354 if (nvgpu_mem_is_valid(&tsg->gr_ctx.mem)) {
355 gr_gk20a_free_tsg_gr_ctx(tsg);
356 }
357
358 if (g->ops.fifo.deinit_eng_method_buffers != NULL) {
359 g->ops.fifo.deinit_eng_method_buffers(g, tsg);
360 }
361
362 if (tsg->vm != NULL) {
363 nvgpu_vm_put(tsg->vm);
364 tsg->vm = NULL;
365 }
366
367 if(tsg->sm_error_states != NULL) {
368 nvgpu_kfree(g, tsg->sm_error_states);
369 tsg->sm_error_states = NULL;
370 }
371
372 /* unhook all events created on this TSG */
373 nvgpu_mutex_acquire(&tsg->event_id_list_lock);
374 nvgpu_list_for_each_entry_safe(event_id_data, event_id_data_temp,
375 &tsg->event_id_list,
376 gk20a_event_id_data,
377 event_id_node) {
378 nvgpu_list_del(&event_id_data->event_id_node);
379 }
380 nvgpu_mutex_release(&tsg->event_id_list_lock);
381
382 release_used_tsg(&g->fifo, tsg);
383
384 tsg->runlist_id = ~0;
385 tsg->sm_exception_mask_type = NVGPU_SM_EXCEPTION_TYPE_MASK_NONE;
386
387 nvgpu_log(g, gpu_dbg_fn, "tsg released %d\n", tsg->tsgid);
388}
389
390struct tsg_gk20a *tsg_gk20a_from_ch(struct channel_gk20a *ch)
391{
392 struct tsg_gk20a *tsg = NULL;
393
394 if (gk20a_is_channel_marked_as_tsg(ch)) {
395 struct gk20a *g = ch->g;
396 struct fifo_gk20a *f = &g->fifo;
397 tsg = &f->tsg[ch->tsgid];
398 }
399
400 return tsg;
401}
402
403int gk20a_tsg_alloc_sm_error_states_mem(struct gk20a *g,
404 struct tsg_gk20a *tsg,
405 u32 num_sm)
406{
407 int err = 0;
408
409 if (tsg->sm_error_states != NULL) {
410 return err;
411 }
412
413 tsg->sm_error_states = nvgpu_kzalloc(g,
414 sizeof(struct nvgpu_tsg_sm_error_state)
415 * num_sm);
416 if (tsg->sm_error_states == NULL) {
417 nvgpu_err(g, "sm_error_states mem allocation failed");
418 err = -ENOMEM;
419 }
420
421 return err;
422}
423
424void gk20a_tsg_update_sm_error_state_locked(struct tsg_gk20a *tsg,
425 u32 sm_id,
426 struct nvgpu_tsg_sm_error_state *sm_error_state)
427{
428 struct nvgpu_tsg_sm_error_state *tsg_sm_error_states;
429
430 tsg_sm_error_states = tsg->sm_error_states + sm_id;
431
432 tsg_sm_error_states->hww_global_esr =
433 sm_error_state->hww_global_esr;
434 tsg_sm_error_states->hww_warp_esr =
435 sm_error_state->hww_warp_esr;
436 tsg_sm_error_states->hww_warp_esr_pc =
437 sm_error_state->hww_warp_esr_pc;
438 tsg_sm_error_states->hww_global_esr_report_mask =
439 sm_error_state->hww_global_esr_report_mask;
440 tsg_sm_error_states->hww_warp_esr_report_mask =
441 sm_error_state->hww_warp_esr_report_mask;
442}