diff options
Diffstat (limited to 'drivers/gpu/nvgpu/common/linux')
-rw-r--r-- | drivers/gpu/nvgpu/common/linux/channel.c | 157 | ||||
-rw-r--r-- | drivers/gpu/nvgpu/common/linux/channel.h | 32 | ||||
-rw-r--r-- | drivers/gpu/nvgpu/common/linux/module.c | 26 | ||||
-rw-r--r-- | drivers/gpu/nvgpu/common/linux/os_linux.h | 2 |
4 files changed, 217 insertions, 0 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 | ||
40 | static 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 | |||
60 | static 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 | |||
70 | static 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 | |||
81 | static 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 | |||
89 | static 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 | |||
97 | struct 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 | |||
119 | static void nvgpu_channel_open_linux(struct channel_gk20a *ch) | ||
120 | { | ||
121 | } | ||
122 | |||
123 | static void nvgpu_channel_close_linux(struct channel_gk20a *ch) | ||
124 | { | ||
125 | nvgpu_channel_work_completion_clear(ch); | ||
126 | } | ||
127 | |||
128 | static 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 | |||
144 | static void nvgpu_channel_free_linux(struct gk20a *g, struct channel_gk20a *ch) | ||
145 | { | ||
146 | nvgpu_kfree(g, ch->os_priv); | ||
147 | } | ||
148 | |||
149 | int 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 | |||
172 | err_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 | |||
181 | void 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 | |||
37 | u32 nvgpu_get_gpfifo_entry_size(void) | 194 | u32 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 | ||
21 | struct channel_gk20a; | 23 | struct channel_gk20a; |
@@ -24,6 +26,36 @@ struct nvgpu_submit_gpfifo_args; | |||
24 | struct nvgpu_fence; | 26 | struct nvgpu_fence; |
25 | struct gk20a_fence; | 27 | struct gk20a_fence; |
26 | struct fifo_profile_gk20a; | 28 | struct fifo_profile_gk20a; |
29 | struct nvgpu_os_linux; | ||
30 | |||
31 | struct 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 | |||
45 | struct nvgpu_channel_linux { | ||
46 | struct channel_gk20a *ch; | ||
47 | |||
48 | struct nvgpu_channel_completion_cb completion_cb; | ||
49 | }; | ||
50 | |||
51 | int nvgpu_init_channel_support_linux(struct nvgpu_os_linux *l); | ||
52 | void nvgpu_remove_channel_support_linux(struct nvgpu_os_linux *l); | ||
53 | |||
54 | struct 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 | ||
28 | int gk20a_submit_channel_gpfifo(struct channel_gk20a *c, | 60 | int 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 | ||
189 | static 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 | |||
188 | int gk20a_pm_finalize_poweron(struct device *dev) | 208 | int 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 | ||
154 | static inline struct nvgpu_os_linux *nvgpu_os_linux_from_gk20a(struct gk20a *g) | 156 | static inline struct nvgpu_os_linux *nvgpu_os_linux_from_gk20a(struct gk20a *g) |