summaryrefslogtreecommitdiffstats
path: root/drivers/gpu/nvgpu/vgpu/vgpu.c
diff options
context:
space:
mode:
authorAingara Paramakuru <aparamakuru@nvidia.com>2014-05-05 21:14:22 -0400
committerDan Willemsen <dwillemsen@nvidia.com>2015-03-18 15:11:01 -0400
commit1fd722f592c2e0523c5e399a2406a4e387057188 (patch)
tree3425fb1a08ec2ccc6397e39c73a5579117e00a05 /drivers/gpu/nvgpu/vgpu/vgpu.c
parent69e0cd3dfd8f39bc8d3529325001dcacd774f669 (diff)
gpu: nvgpu: support gk20a virtualization
The nvgpu driver now supports using the Tegra graphics virtualization interfaces to support gk20a in a virtualized environment. Bug 1509608 Change-Id: I6ede15ee7bf0b0ad8a13e8eb5f557c3516ead676 Signed-off-by: Aingara Paramakuru <aparamakuru@nvidia.com> Reviewed-on: http://git-master/r/440122 Reviewed-by: Terje Bergstrom <tbergstrom@nvidia.com> Tested-by: Terje Bergstrom <tbergstrom@nvidia.com>
Diffstat (limited to 'drivers/gpu/nvgpu/vgpu/vgpu.c')
-rw-r--r--drivers/gpu/nvgpu/vgpu/vgpu.c416
1 files changed, 416 insertions, 0 deletions
diff --git a/drivers/gpu/nvgpu/vgpu/vgpu.c b/drivers/gpu/nvgpu/vgpu/vgpu.c
new file mode 100644
index 00000000..cfe307ff
--- /dev/null
+++ b/drivers/gpu/nvgpu/vgpu/vgpu.c
@@ -0,0 +1,416 @@
1/*
2 * Virtualized GPU
3 *
4 * Copyright (c) 2014 NVIDIA CORPORATION. All rights reserved.
5 *
6 * This program is free software; you can redistribute it and/or modify it
7 * under the terms and conditions of the GNU General Public License,
8 * version 2, as published by the Free Software Foundation.
9 *
10 * This program is distributed in the hope it will be useful, but WITHOUT
11 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
12 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
13 * more details.
14 */
15
16#include <linux/kthread.h>
17#include <linux/delay.h>
18#include <linux/dma-mapping.h>
19#include <linux/pm_runtime.h>
20#include "vgpu/vgpu.h"
21#include "gk20a/debug_gk20a.h"
22#include "gk20a/hal_gk20a.h"
23#include "gk20a/hw_mc_gk20a.h"
24
25static inline int vgpu_comm_init(struct platform_device *pdev)
26{
27 size_t queue_sizes[] = { TEGRA_VGPU_QUEUE_SIZES };
28
29 return tegra_gr_comm_init(pdev, TEGRA_GR_COMM_CTX_CLIENT, 3,
30 queue_sizes, TEGRA_VGPU_QUEUE_CMD,
31 ARRAY_SIZE(queue_sizes));
32}
33
34static inline void vgpu_comm_deinit(void)
35{
36 size_t queue_sizes[] = { TEGRA_VGPU_QUEUE_SIZES };
37
38 tegra_gr_comm_deinit(TEGRA_GR_COMM_CTX_CLIENT, TEGRA_VGPU_QUEUE_CMD,
39 ARRAY_SIZE(queue_sizes));
40}
41
42int vgpu_comm_sendrecv(struct tegra_vgpu_cmd_msg *msg, size_t size_in,
43 size_t size_out)
44{
45 void *handle;
46 size_t size = size_in;
47 void *data = msg;
48 int err;
49
50 err = tegra_gr_comm_sendrecv(TEGRA_GR_COMM_CTX_CLIENT,
51 tegra_gr_comm_get_server_vmid(),
52 TEGRA_VGPU_QUEUE_CMD, &handle, &data, &size);
53 if (!err) {
54 WARN_ON(size < size_out);
55 memcpy(msg, data, size_out);
56 tegra_gr_comm_release(handle);
57 }
58
59 return err;
60}
61
62static u64 vgpu_connect(void)
63{
64 struct tegra_vgpu_cmd_msg msg;
65 struct tegra_vgpu_connect_params *p = &msg.params.connect;
66 int err;
67
68 msg.cmd = TEGRA_VGPU_CMD_CONNECT;
69 p->module = TEGRA_VGPU_MODULE_GPU;
70 err = vgpu_comm_sendrecv(&msg, sizeof(msg), sizeof(msg));
71
72 return (err || msg.ret) ? 0 : p->handle;
73}
74
75int vgpu_get_attribute(u64 handle, u32 attrib, u32 *value)
76{
77 struct tegra_vgpu_cmd_msg msg;
78 struct tegra_vgpu_attrib_params *p = &msg.params.attrib;
79 int err;
80
81 msg.cmd = TEGRA_VGPU_CMD_GET_ATTRIBUTE;
82 msg.handle = handle;
83 p->attrib = attrib;
84 err = vgpu_comm_sendrecv(&msg, sizeof(msg), sizeof(msg));
85
86 if (err || msg.ret)
87 return -1;
88
89 *value = p->value;
90 return 0;
91}
92
93static int vgpu_intr_thread(void *dev_id)
94{
95 struct gk20a *g = dev_id;
96
97 while (true) {
98 struct tegra_vgpu_intr_msg *msg;
99 u32 sender;
100 void *handle;
101 size_t size;
102 int err;
103
104 err = tegra_gr_comm_recv(TEGRA_GR_COMM_CTX_CLIENT,
105 TEGRA_VGPU_QUEUE_INTR, &handle,
106 (void **)&msg, &size, &sender);
107 if (WARN_ON(err))
108 continue;
109
110 if (msg->event == TEGRA_VGPU_EVENT_ABORT) {
111 tegra_gr_comm_release(handle);
112 break;
113 }
114
115 if (msg->unit == TEGRA_VGPU_INTR_GR)
116 vgpu_gr_isr(g, &msg->info.gr_intr);
117
118 tegra_gr_comm_release(handle);
119 }
120
121 while (!kthread_should_stop())
122 msleep(10);
123 return 0;
124}
125
126static void vgpu_remove_support(struct platform_device *dev)
127{
128 struct gk20a *g = get_gk20a(dev);
129 struct gk20a_platform *platform = gk20a_get_platform(dev);
130 struct tegra_vgpu_intr_msg msg;
131 int err;
132
133 if (g->pmu.remove_support)
134 g->pmu.remove_support(&g->pmu);
135
136 if (g->gr.remove_support)
137 g->gr.remove_support(&g->gr);
138
139 if (g->fifo.remove_support)
140 g->fifo.remove_support(&g->fifo);
141
142 if (g->mm.remove_support)
143 g->mm.remove_support(&g->mm);
144
145 msg.event = TEGRA_VGPU_EVENT_ABORT;
146 err = tegra_gr_comm_send(TEGRA_GR_COMM_CTX_CLIENT,
147 TEGRA_GR_COMM_ID_SELF, TEGRA_VGPU_QUEUE_INTR,
148 &msg, sizeof(msg));
149 WARN_ON(err);
150 kthread_stop(platform->intr_handler);
151
152 /* free mappings to registers, etc*/
153
154 if (g->bar1) {
155 iounmap(g->bar1);
156 g->bar1 = 0;
157 }
158}
159
160static int vgpu_init_support(struct platform_device *dev)
161{
162 struct resource *r = platform_get_resource(dev, IORESOURCE_MEM, 0);
163 struct gk20a *g = get_gk20a(dev);
164 int err = 0;
165
166 if (!r) {
167 dev_err(dev_from_gk20a(g), "faield to get gk20a bar1\n");
168 err = -ENXIO;
169 goto fail;
170 }
171
172 g->bar1 = devm_request_and_ioremap(&dev->dev, r);
173 if (!g->bar1) {
174 dev_err(dev_from_gk20a(g), "failed to remap gk20a bar1\n");
175 err = -ENXIO;
176 goto fail;
177 }
178
179 mutex_init(&g->dbg_sessions_lock);
180 mutex_init(&g->client_lock);
181
182 g->remove_support = vgpu_remove_support;
183 return 0;
184
185 fail:
186 vgpu_remove_support(dev);
187 return err;
188}
189
190int vgpu_pm_prepare_poweroff(struct device *dev)
191{
192 struct platform_device *pdev = to_platform_device(dev);
193 struct gk20a *g = get_gk20a(pdev);
194 int ret = 0;
195
196 gk20a_dbg_fn("");
197
198 if (!g->power_on)
199 return 0;
200
201 ret = gk20a_channel_suspend(g);
202 if (ret)
203 return ret;
204
205 g->power_on = false;
206
207 return ret;
208}
209
210static void vgpu_detect_chip(struct gk20a *g)
211{
212 struct nvhost_gpu_characteristics *gpu = &g->gpu_characteristics;
213 struct gk20a_platform *platform = gk20a_get_platform(g->dev);
214
215 u32 mc_boot_0_value;
216
217 if (vgpu_get_attribute(platform->virt_handle,
218 TEGRA_VGPU_ATTRIB_PMC_BOOT_0,
219 &mc_boot_0_value)) {
220 gk20a_err(dev_from_gk20a(g), "failed to detect chip");
221 return;
222 }
223
224 gpu->arch = mc_boot_0_architecture_v(mc_boot_0_value) <<
225 NVHOST_GPU_ARCHITECTURE_SHIFT;
226 gpu->impl = mc_boot_0_implementation_v(mc_boot_0_value);
227 gpu->rev =
228 (mc_boot_0_major_revision_v(mc_boot_0_value) << 4) |
229 mc_boot_0_minor_revision_v(mc_boot_0_value);
230
231 gk20a_dbg_info("arch: %x, impl: %x, rev: %x\n",
232 g->gpu_characteristics.arch,
233 g->gpu_characteristics.impl,
234 g->gpu_characteristics.rev);
235}
236
237static int vgpu_init_hal(struct gk20a *g)
238{
239 u32 ver = g->gpu_characteristics.arch + g->gpu_characteristics.impl;
240
241 switch (ver) {
242 case GK20A_GPUID_GK20A:
243 gk20a_dbg_info("gk20a detected");
244 /* init gk20a ops then override with virt extensions */
245 gk20a_init_hal(&g->ops);
246 vgpu_init_fifo_ops(&g->ops);
247 vgpu_init_gr_ops(&g->ops);
248 vgpu_init_ltc_ops(&g->ops);
249 vgpu_init_mm_ops(&g->ops);
250 break;
251 default:
252 gk20a_err(&g->dev->dev, "no support for %x", ver);
253 return -ENODEV;
254 }
255
256 return 0;
257}
258
259int vgpu_pm_finalize_poweron(struct device *dev)
260{
261 struct platform_device *pdev = to_platform_device(dev);
262 struct gk20a *g = get_gk20a(pdev);
263 int err;
264
265 gk20a_dbg_fn("");
266
267 if (g->power_on)
268 return 0;
269
270 g->power_on = true;
271
272 vgpu_detect_chip(g);
273 err = vgpu_init_hal(g);
274 if (err)
275 goto done;
276
277 err = vgpu_init_mm_support(g);
278 if (err) {
279 gk20a_err(dev, "failed to init gk20a mm");
280 goto done;
281 }
282
283 err = vgpu_init_fifo_support(g);
284 if (err) {
285 gk20a_err(dev, "failed to init gk20a fifo");
286 goto done;
287 }
288
289 err = vgpu_init_gr_support(g);
290 if (err) {
291 gk20a_err(dev, "failed to init gk20a gr");
292 goto done;
293 }
294
295 err = gk20a_init_gpu_characteristics(g);
296 if (err) {
297 gk20a_err(dev, "failed to init gk20a gpu characteristics");
298 goto done;
299 }
300
301 gk20a_channel_resume(g);
302
303done:
304 return err;
305}
306
307static int vgpu_pm_init(struct platform_device *dev)
308{
309 int err = 0;
310
311 gk20a_dbg_fn("");
312
313 pm_runtime_enable(&dev->dev);
314 return err;
315}
316
317int vgpu_probe(struct platform_device *dev)
318{
319 struct gk20a *gk20a;
320 int err;
321 struct gk20a_platform *platform = gk20a_get_platform(dev);
322
323 if (!platform) {
324 dev_err(&dev->dev, "no platform data\n");
325 return -ENODATA;
326 }
327
328 gk20a_dbg_fn("");
329
330 gk20a = kzalloc(sizeof(struct gk20a), GFP_KERNEL);
331 if (!gk20a) {
332 dev_err(&dev->dev, "couldn't allocate gk20a support");
333 return -ENOMEM;
334 }
335
336 platform->g = gk20a;
337 gk20a->dev = dev;
338
339 err = gk20a_user_init(dev);
340 if (err)
341 return err;
342
343 vgpu_init_support(dev);
344
345 init_rwsem(&gk20a->busy_lock);
346
347 spin_lock_init(&gk20a->mc_enable_lock);
348
349 /* Initialize the platform interface. */
350 err = platform->probe(dev);
351 if (err) {
352 dev_err(&dev->dev, "platform probe failed");
353 return err;
354 }
355
356 err = vgpu_pm_init(dev);
357 if (err) {
358 dev_err(&dev->dev, "pm init failed");
359 return err;
360 }
361
362 if (platform->late_probe) {
363 err = platform->late_probe(dev);
364 if (err) {
365 dev_err(&dev->dev, "late probe failed");
366 return err;
367 }
368 }
369
370 err = vgpu_comm_init(dev);
371 if (err) {
372 dev_err(&dev->dev, "failed to init comm interface\n");
373 return -ENOSYS;
374 }
375
376 platform->virt_handle = vgpu_connect();
377 if (!platform->virt_handle) {
378 dev_err(&dev->dev, "failed to connect to server node\n");
379 vgpu_comm_deinit();
380 return -ENOSYS;
381 }
382
383 platform->intr_handler = kthread_run(vgpu_intr_thread, gk20a, "gk20a");
384 if (IS_ERR(platform->intr_handler))
385 return -ENOMEM;
386
387 gk20a_debug_init(dev);
388
389 /* Set DMA parameters to allow larger sgt lists */
390 dev->dev.dma_parms = &gk20a->dma_parms;
391 dma_set_max_seg_size(&dev->dev, UINT_MAX);
392
393 gk20a->gr_idle_timeout_default =
394 CONFIG_GK20A_DEFAULT_TIMEOUT;
395 gk20a->timeouts_enabled = true;
396
397 gk20a_create_sysfs(dev);
398 gk20a_init_gr(gk20a);
399
400 return 0;
401}
402
403int vgpu_remove(struct platform_device *dev)
404{
405 struct gk20a *g = get_gk20a(dev);
406 gk20a_dbg_fn("");
407
408 if (g->remove_support)
409 g->remove_support(dev);
410
411 vgpu_comm_deinit();
412 gk20a_user_deinit(dev);
413 gk20a_get_platform(dev)->g = NULL;
414 kfree(g);
415 return 0;
416}