summaryrefslogtreecommitdiffstats
path: root/drivers/gpu/nvgpu
diff options
context:
space:
mode:
authorKonsta Holtta <kholtta@nvidia.com>2017-11-22 08:57:11 -0500
committermobile promotions <svcmobile_promotions@nvidia.com>2017-11-22 20:18:56 -0500
commitba2e59dc41f593bb011e0ec58c969337a35f4cf1 (patch)
tree12a4fcec144516a0e903e5495898e9072d7db27c /drivers/gpu/nvgpu
parentb498f4c5c0a0a5f1a59a9210a1ee4d1d8ae98be7 (diff)
gpu: nvgpu: use submit callback only in linux code
Move the implementation for channel job update callbacks that is based on Linux specific work_struct usage to Linux-specific code. This requires a bit of extra work for allocating OS-specific priv data for channels which is also done in this patch. The priv data will be used more when more OS-specific features are moved. Jira NVGPU-259 Change-Id: I24bc0148a827f375b56a1c96044685affc2d1e8c Signed-off-by: Konsta Holtta <kholtta@nvidia.com> Reviewed-on: https://git-master.nvidia.com/r/1589321 Reviewed-by: mobile promotions <svcmobile_promotions@nvidia.com> Tested-by: mobile promotions <svcmobile_promotions@nvidia.com>
Diffstat (limited to 'drivers/gpu/nvgpu')
-rw-r--r--drivers/gpu/nvgpu/common/linux/channel.c157
-rw-r--r--drivers/gpu/nvgpu/common/linux/channel.h32
-rw-r--r--drivers/gpu/nvgpu/common/linux/module.c26
-rw-r--r--drivers/gpu/nvgpu/common/linux/os_linux.h2
-rw-r--r--drivers/gpu/nvgpu/gk20a/channel_gk20a.c57
-rw-r--r--drivers/gpu/nvgpu/gk20a/channel_gk20a.h21
-rw-r--r--drivers/gpu/nvgpu/gk20a/gk20a.h7
7 files changed, 236 insertions, 66 deletions
diff --git a/drivers/gpu/nvgpu/common/linux/channel.c b/drivers/gpu/nvgpu/common/linux/channel.c
index 40b11b86..8366ed88 100644
--- a/drivers/gpu/nvgpu/common/linux/channel.c
+++ b/drivers/gpu/nvgpu/common/linux/channel.c
@@ -27,6 +27,9 @@
27 27
28#include "gk20a/gk20a.h" 28#include "gk20a/gk20a.h"
29 29
30#include "channel.h"
31#include "os_linux.h"
32
30#include <nvgpu/hw/gk20a/hw_pbdma_gk20a.h> 33#include <nvgpu/hw/gk20a/hw_pbdma_gk20a.h>
31 34
32#include <linux/uaccess.h> 35#include <linux/uaccess.h>
@@ -34,6 +37,160 @@
34#include <trace/events/gk20a.h> 37#include <trace/events/gk20a.h>
35#include <uapi/linux/nvgpu.h> 38#include <uapi/linux/nvgpu.h>
36 39
40static void gk20a_channel_update_runcb_fn(struct work_struct *work)
41{
42 struct nvgpu_channel_completion_cb *completion_cb =
43 container_of(work, struct nvgpu_channel_completion_cb, work);
44 struct nvgpu_channel_linux *priv =
45 container_of(completion_cb,
46 struct nvgpu_channel_linux, completion_cb);
47 struct channel_gk20a *ch = priv->ch;
48 void (*fn)(struct channel_gk20a *, void *);
49 void *user_data;
50
51 nvgpu_spinlock_acquire(&completion_cb->lock);
52 fn = completion_cb->fn;
53 user_data = completion_cb->user_data;
54 nvgpu_spinlock_release(&completion_cb->lock);
55
56 if (fn)
57 fn(ch, user_data);
58}
59
60static void nvgpu_channel_work_completion_init(struct channel_gk20a *ch)
61{
62 struct nvgpu_channel_linux *priv = ch->os_priv;
63
64 priv->completion_cb.fn = NULL;
65 priv->completion_cb.user_data = NULL;
66 nvgpu_spinlock_init(&priv->completion_cb.lock);
67 INIT_WORK(&priv->completion_cb.work, gk20a_channel_update_runcb_fn);
68}
69
70static void nvgpu_channel_work_completion_clear(struct channel_gk20a *ch)
71{
72 struct nvgpu_channel_linux *priv = ch->os_priv;
73
74 nvgpu_spinlock_acquire(&priv->completion_cb.lock);
75 priv->completion_cb.fn = NULL;
76 priv->completion_cb.user_data = NULL;
77 nvgpu_spinlock_release(&priv->completion_cb.lock);
78 cancel_work_sync(&priv->completion_cb.work);
79}
80
81static void nvgpu_channel_work_completion_signal(struct channel_gk20a *ch)
82{
83 struct nvgpu_channel_linux *priv = ch->os_priv;
84
85 if (priv->completion_cb.fn)
86 schedule_work(&priv->completion_cb.work);
87}
88
89static void nvgpu_channel_work_completion_cancel_sync(struct channel_gk20a *ch)
90{
91 struct nvgpu_channel_linux *priv = ch->os_priv;
92
93 if (priv->completion_cb.fn)
94 cancel_work_sync(&priv->completion_cb.work);
95}
96
97struct channel_gk20a *gk20a_open_new_channel_with_cb(struct gk20a *g,
98 void (*update_fn)(struct channel_gk20a *, void *),
99 void *update_fn_data,
100 int runlist_id,
101 bool is_privileged_channel)
102{
103 struct channel_gk20a *ch;
104 struct nvgpu_channel_linux *priv;
105
106 ch = gk20a_open_new_channel(g, runlist_id, is_privileged_channel);
107
108 if (ch) {
109 priv = ch->os_priv;
110 nvgpu_spinlock_acquire(&priv->completion_cb.lock);
111 priv->completion_cb.fn = update_fn;
112 priv->completion_cb.user_data = update_fn_data;
113 nvgpu_spinlock_release(&priv->completion_cb.lock);
114 }
115
116 return ch;
117}
118
119static void nvgpu_channel_open_linux(struct channel_gk20a *ch)
120{
121}
122
123static void nvgpu_channel_close_linux(struct channel_gk20a *ch)
124{
125 nvgpu_channel_work_completion_clear(ch);
126}
127
128static int nvgpu_channel_alloc_linux(struct gk20a *g, struct channel_gk20a *ch)
129{
130 struct nvgpu_channel_linux *priv;
131
132 priv = nvgpu_kzalloc(g, sizeof(*priv));
133 if (!priv)
134 return -ENOMEM;
135
136 ch->os_priv = priv;
137 priv->ch = ch;
138
139 nvgpu_channel_work_completion_init(ch);
140
141 return 0;
142}
143
144static void nvgpu_channel_free_linux(struct gk20a *g, struct channel_gk20a *ch)
145{
146 nvgpu_kfree(g, ch->os_priv);
147}
148
149int nvgpu_init_channel_support_linux(struct nvgpu_os_linux *l)
150{
151 struct gk20a *g = &l->g;
152 struct fifo_gk20a *f = &g->fifo;
153 int chid;
154 int err;
155
156 for (chid = 0; chid < (int)f->num_channels; chid++) {
157 struct channel_gk20a *ch = &f->channel[chid];
158
159 err = nvgpu_channel_alloc_linux(g, ch);
160 if (err)
161 goto err_clean;
162 }
163
164 g->os_channel.open = nvgpu_channel_open_linux;
165 g->os_channel.close = nvgpu_channel_close_linux;
166 g->os_channel.work_completion_signal =
167 nvgpu_channel_work_completion_signal;
168 g->os_channel.work_completion_cancel_sync =
169 nvgpu_channel_work_completion_cancel_sync;
170 return 0;
171
172err_clean:
173 for (; chid >= 0; chid--) {
174 struct channel_gk20a *ch = &f->channel[chid];
175
176 nvgpu_channel_free_linux(g, ch);
177 }
178 return err;
179}
180
181void nvgpu_remove_channel_support_linux(struct nvgpu_os_linux *l)
182{
183 struct gk20a *g = &l->g;
184 struct fifo_gk20a *f = &g->fifo;
185 unsigned int chid;
186
187 for (chid = 0; chid < f->num_channels; chid++) {
188 struct channel_gk20a *ch = &f->channel[chid];
189
190 nvgpu_channel_free_linux(g, ch);
191 }
192}
193
37u32 nvgpu_get_gpfifo_entry_size(void) 194u32 nvgpu_get_gpfifo_entry_size(void)
38{ 195{
39 return sizeof(struct nvgpu_gpfifo); 196 return sizeof(struct nvgpu_gpfifo);
diff --git a/drivers/gpu/nvgpu/common/linux/channel.h b/drivers/gpu/nvgpu/common/linux/channel.h
index 785c03d6..ba1935f3 100644
--- a/drivers/gpu/nvgpu/common/linux/channel.h
+++ b/drivers/gpu/nvgpu/common/linux/channel.h
@@ -16,6 +16,8 @@
16#ifndef __NVGPU_CHANNEL_H__ 16#ifndef __NVGPU_CHANNEL_H__
17#define __NVGPU_CHANNEL_H__ 17#define __NVGPU_CHANNEL_H__
18 18
19#include <linux/workqueue.h>
20
19#include <nvgpu/types.h> 21#include <nvgpu/types.h>
20 22
21struct channel_gk20a; 23struct channel_gk20a;
@@ -24,6 +26,36 @@ struct nvgpu_submit_gpfifo_args;
24struct nvgpu_fence; 26struct nvgpu_fence;
25struct gk20a_fence; 27struct gk20a_fence;
26struct fifo_profile_gk20a; 28struct fifo_profile_gk20a;
29struct nvgpu_os_linux;
30
31struct nvgpu_channel_completion_cb {
32 /*
33 * Signal channel owner via a callback, if set, in job cleanup with
34 * schedule_work. Means that something finished on the channel (perhaps
35 * more than one job).
36 */
37 void (*fn)(struct channel_gk20a *, void *);
38 void *user_data;
39 /* Make access to the two above atomic */
40 struct nvgpu_spinlock lock;
41 /* Per-channel async work task, cannot reschedule itself */
42 struct work_struct work;
43};
44
45struct nvgpu_channel_linux {
46 struct channel_gk20a *ch;
47
48 struct nvgpu_channel_completion_cb completion_cb;
49};
50
51int nvgpu_init_channel_support_linux(struct nvgpu_os_linux *l);
52void nvgpu_remove_channel_support_linux(struct nvgpu_os_linux *l);
53
54struct channel_gk20a *gk20a_open_new_channel_with_cb(struct gk20a *g,
55 void (*update_fn)(struct channel_gk20a *, void *),
56 void *update_fn_data,
57 int runlist_id,
58 bool is_privileged_channel);
27 59
28int gk20a_submit_channel_gpfifo(struct channel_gk20a *c, 60int gk20a_submit_channel_gpfifo(struct channel_gk20a *c,
29 struct nvgpu_gpfifo *gpfifo, 61 struct nvgpu_gpfifo *gpfifo,
diff --git a/drivers/gpu/nvgpu/common/linux/module.c b/drivers/gpu/nvgpu/common/linux/module.c
index 796507a9..5012d8b5 100644
--- a/drivers/gpu/nvgpu/common/linux/module.c
+++ b/drivers/gpu/nvgpu/common/linux/module.c
@@ -59,6 +59,7 @@
59#include "cde_gp10b.h" 59#include "cde_gp10b.h"
60#include "ctxsw_trace.h" 60#include "ctxsw_trace.h"
61#include "driver_common.h" 61#include "driver_common.h"
62#include "channel.h"
62 63
63#define CLASS_NAME "nvidia-gpu" 64#define CLASS_NAME "nvidia-gpu"
64/* TODO: Change to e.g. "nvidia-gpu%s" once we have symlinks in place. */ 65/* TODO: Change to e.g. "nvidia-gpu%s" once we have symlinks in place. */
@@ -185,6 +186,25 @@ static int nvgpu_init_os_linux_ops(struct nvgpu_os_linux *l)
185 return 0; 186 return 0;
186} 187}
187 188
189static int nvgpu_finalize_poweron_linux(struct nvgpu_os_linux *l)
190{
191 struct gk20a *g = &l->g;
192 int err;
193
194 if (l->init_done)
195 return 0;
196
197 err = nvgpu_init_channel_support_linux(l);
198 if (err) {
199 nvgpu_err(g, "failed to init linux channel support");
200 return err;
201 }
202
203 l->init_done = true;
204
205 return 0;
206}
207
188int gk20a_pm_finalize_poweron(struct device *dev) 208int gk20a_pm_finalize_poweron(struct device *dev)
189{ 209{
190 struct gk20a *g = get_gk20a(dev); 210 struct gk20a *g = get_gk20a(dev);
@@ -227,6 +247,10 @@ int gk20a_pm_finalize_poweron(struct device *dev)
227 if (err) 247 if (err)
228 goto done; 248 goto done;
229 249
250 err = nvgpu_finalize_poweron_linux(l);
251 if (err)
252 goto done;
253
230 trace_gk20a_finalize_poweron_done(dev_name(dev)); 254 trace_gk20a_finalize_poweron_done(dev_name(dev));
231 255
232 err = nvgpu_init_os_linux_ops(l); 256 err = nvgpu_init_os_linux_ops(l);
@@ -596,6 +620,8 @@ void gk20a_remove_support(struct gk20a *g)
596 620
597 nvgpu_kfree(g, g->dbg_regops_tmp_buf); 621 nvgpu_kfree(g, g->dbg_regops_tmp_buf);
598 622
623 nvgpu_remove_channel_support_linux(l);
624
599 if (g->pmu.remove_support) 625 if (g->pmu.remove_support)
600 g->pmu.remove_support(&g->pmu); 626 g->pmu.remove_support(&g->pmu);
601 627
diff --git a/drivers/gpu/nvgpu/common/linux/os_linux.h b/drivers/gpu/nvgpu/common/linux/os_linux.h
index 07be7edc..9b95ed84 100644
--- a/drivers/gpu/nvgpu/common/linux/os_linux.h
+++ b/drivers/gpu/nvgpu/common/linux/os_linux.h
@@ -149,6 +149,8 @@ struct nvgpu_os_linux {
149 struct rw_semaphore busy_lock; 149 struct rw_semaphore busy_lock;
150 150
151 struct gk20a_sched_ctrl sched_ctrl; 151 struct gk20a_sched_ctrl sched_ctrl;
152
153 bool init_done;
152}; 154};
153 155
154static inline struct nvgpu_os_linux *nvgpu_os_linux_from_gk20a(struct gk20a *g) 156static inline struct nvgpu_os_linux *nvgpu_os_linux_from_gk20a(struct gk20a *g)
diff --git a/drivers/gpu/nvgpu/gk20a/channel_gk20a.c b/drivers/gpu/nvgpu/gk20a/channel_gk20a.c
index 4be232f1..e01d6cdb 100644
--- a/drivers/gpu/nvgpu/gk20a/channel_gk20a.c
+++ b/drivers/gpu/nvgpu/gk20a/channel_gk20a.c
@@ -444,6 +444,9 @@ static void gk20a_free_channel(struct channel_gk20a *ch, bool force)
444 444
445 trace_gk20a_free_channel(ch->chid); 445 trace_gk20a_free_channel(ch->chid);
446 446
447 if (g->os_channel.close)
448 g->os_channel.close(ch);
449
447 /* 450 /*
448 * Disable channel/TSG and unbind here. This should not be executed if 451 * Disable channel/TSG and unbind here. This should not be executed if
449 * HW access is not available during shutdown/removal path as it will 452 * HW access is not available during shutdown/removal path as it will
@@ -561,12 +564,6 @@ static void gk20a_free_channel(struct channel_gk20a *ch, bool force)
561 */ 564 */
562 nvgpu_vm_put(ch_vm); 565 nvgpu_vm_put(ch_vm);
563 566
564 nvgpu_spinlock_acquire(&ch->update_fn_lock);
565 ch->update_fn = NULL;
566 ch->update_fn_data = NULL;
567 nvgpu_spinlock_release(&ch->update_fn_lock);
568 cancel_work_sync(&ch->update_fn_work);
569
570 /* make sure we don't have deferred interrupts pending that 567 /* make sure we don't have deferred interrupts pending that
571 * could still touch the channel */ 568 * could still touch the channel */
572 nvgpu_wait_for_deferred_interrupts(g); 569 nvgpu_wait_for_deferred_interrupts(g);
@@ -756,40 +753,6 @@ void __gk20a_channel_kill(struct channel_gk20a *ch)
756 gk20a_free_channel(ch, true); 753 gk20a_free_channel(ch, true);
757} 754}
758 755
759static void gk20a_channel_update_runcb_fn(struct work_struct *work)
760{
761 struct channel_gk20a *ch =
762 container_of(work, struct channel_gk20a, update_fn_work);
763 void (*update_fn)(struct channel_gk20a *, void *);
764 void *update_fn_data;
765
766 nvgpu_spinlock_acquire(&ch->update_fn_lock);
767 update_fn = ch->update_fn;
768 update_fn_data = ch->update_fn_data;
769 nvgpu_spinlock_release(&ch->update_fn_lock);
770
771 if (update_fn)
772 update_fn(ch, update_fn_data);
773}
774
775struct channel_gk20a *gk20a_open_new_channel_with_cb(struct gk20a *g,
776 void (*update_fn)(struct channel_gk20a *, void *),
777 void *update_fn_data,
778 int runlist_id,
779 bool is_privileged_channel)
780{
781 struct channel_gk20a *ch = gk20a_open_new_channel(g, runlist_id, is_privileged_channel);
782
783 if (ch) {
784 nvgpu_spinlock_acquire(&ch->update_fn_lock);
785 ch->update_fn = update_fn;
786 ch->update_fn_data = update_fn_data;
787 nvgpu_spinlock_release(&ch->update_fn_lock);
788 }
789
790 return ch;
791}
792
793struct channel_gk20a *gk20a_open_new_channel(struct gk20a *g, 756struct channel_gk20a *gk20a_open_new_channel(struct gk20a *g,
794 s32 runlist_id, 757 s32 runlist_id,
795 bool is_privileged_channel) 758 bool is_privileged_channel)
@@ -872,10 +835,8 @@ struct channel_gk20a *gk20a_open_new_channel(struct gk20a *g,
872 nvgpu_cond_init(&ch->notifier_wq); 835 nvgpu_cond_init(&ch->notifier_wq);
873 nvgpu_cond_init(&ch->semaphore_wq); 836 nvgpu_cond_init(&ch->semaphore_wq);
874 837
875 ch->update_fn = NULL; 838 if (g->os_channel.open)
876 ch->update_fn_data = NULL; 839 g->os_channel.open(ch);
877 nvgpu_spinlock_init(&ch->update_fn_lock);
878 INIT_WORK(&ch->update_fn_work, gk20a_channel_update_runcb_fn);
879 840
880 /* Mark the channel alive, get-able, with 1 initial use 841 /* Mark the channel alive, get-able, with 1 initial use
881 * references. The initial reference will be decreased in 842 * references. The initial reference will be decreased in
@@ -2120,8 +2081,8 @@ void gk20a_channel_clean_up_jobs(struct channel_gk20a *c,
2120 2081
2121 nvgpu_mutex_release(&c->joblist.cleanup_lock); 2082 nvgpu_mutex_release(&c->joblist.cleanup_lock);
2122 2083
2123 if (job_finished && c->update_fn) 2084 if (job_finished && g->os_channel.work_completion_signal)
2124 schedule_work(&c->update_fn_work); 2085 g->os_channel.work_completion_signal(c);
2125 2086
2126 gk20a_channel_put(c); 2087 gk20a_channel_put(c);
2127} 2088}
@@ -2322,8 +2283,8 @@ int gk20a_channel_suspend(struct gk20a *g)
2322 /* preempt the channel */ 2283 /* preempt the channel */
2323 gk20a_fifo_preempt(g, ch); 2284 gk20a_fifo_preempt(g, ch);
2324 /* wait for channel update notifiers */ 2285 /* wait for channel update notifiers */
2325 if (ch->update_fn) 2286 if (g->os_channel.work_completion_cancel_sync)
2326 cancel_work_sync(&ch->update_fn_work); 2287 g->os_channel.work_completion_cancel_sync(ch);
2327 2288
2328 channels_in_use = true; 2289 channels_in_use = true;
2329 2290
diff --git a/drivers/gpu/nvgpu/gk20a/channel_gk20a.h b/drivers/gpu/nvgpu/gk20a/channel_gk20a.h
index d865849b..8c9095b2 100644
--- a/drivers/gpu/nvgpu/gk20a/channel_gk20a.h
+++ b/drivers/gpu/nvgpu/gk20a/channel_gk20a.h
@@ -24,9 +24,6 @@
24#ifndef CHANNEL_GK20A_H 24#ifndef CHANNEL_GK20A_H
25#define CHANNEL_GK20A_H 25#define CHANNEL_GK20A_H
26 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> 27#include <nvgpu/list.h>
31#include <nvgpu/lock.h> 28#include <nvgpu/lock.h>
32#include <nvgpu/timers.h> 29#include <nvgpu/timers.h>
@@ -288,16 +285,6 @@ struct channel_gk20a {
288 u64 virt_ctx; 285 u64 virt_ctx;
289#endif 286#endif
290 287
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; 288 u32 interleave_level;
302 289
303 u32 runlist_id; 290 u32 runlist_id;
@@ -306,6 +293,9 @@ struct channel_gk20a {
306#ifdef CONFIG_TEGRA_19x_GPU 293#ifdef CONFIG_TEGRA_19x_GPU
307 struct channel_t19x t19x; 294 struct channel_t19x t19x;
308#endif 295#endif
296
297 /* Any operating system specific data. */
298 void *os_priv;
309}; 299};
310 300
311static inline struct channel_gk20a * 301static inline struct channel_gk20a *
@@ -382,11 +372,6 @@ int gk20a_wait_channel_idle(struct channel_gk20a *ch);
382struct channel_gk20a *gk20a_open_new_channel(struct gk20a *g, 372struct channel_gk20a *gk20a_open_new_channel(struct gk20a *g,
383 s32 runlist_id, 373 s32 runlist_id,
384 bool is_privileged_channel); 374 bool is_privileged_channel);
385struct 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 375
391int gk20a_channel_alloc_gpfifo(struct channel_gk20a *c, 376int gk20a_channel_alloc_gpfifo(struct channel_gk20a *c,
392 unsigned int num_entries, 377 unsigned int num_entries,
diff --git a/drivers/gpu/nvgpu/gk20a/gk20a.h b/drivers/gpu/nvgpu/gk20a/gk20a.h
index 8d6db4c7..11a99bff 100644
--- a/drivers/gpu/nvgpu/gk20a/gk20a.h
+++ b/drivers/gpu/nvgpu/gk20a/gk20a.h
@@ -1255,6 +1255,13 @@ struct gk20a {
1255 struct nvgpu_mutex start_lock; 1255 struct nvgpu_mutex start_lock;
1256 } channel_worker; 1256 } channel_worker;
1257 1257
1258 struct {
1259 void (*open)(struct channel_gk20a *ch);
1260 void (*close)(struct channel_gk20a *ch);
1261 void (*work_completion_signal)(struct channel_gk20a *ch);
1262 void (*work_completion_cancel_sync)(struct channel_gk20a *ch);
1263 } os_channel;
1264
1258 struct gk20a_scale_profile *scale_profile; 1265 struct gk20a_scale_profile *scale_profile;
1259 unsigned long last_freq; 1266 unsigned long last_freq;
1260 1267