]>
Commit | Line | Data |
---|---|---|
7eafdf33 | 1 | M/ |
af0f7570 KK |
2 | diff --git a/drivers/gpu/Makefile b/drivers/gpu/Makefile |
3 | index 30879df..35699a0 100644 | |
4 | --- a/drivers/gpu/Makefile | |
5 | +++ b/drivers/gpu/Makefile | |
6 | @@ -1 +1 @@ | |
7 | -obj-y += drm/ vga/ stub/ | |
8 | +obj-y += drm/ vga/ stub/ misc/ | |
9 | diff --git a/drivers/gpu/misc/Kconfig b/drivers/gpu/misc/Kconfig | |
10 | new file mode 100644 | |
11 | index 0000000..50043d3 | |
12 | --- /dev/null | |
13 | +++ b/drivers/gpu/misc/Kconfig | |
14 | @@ -0,0 +1,8 @@ | |
15 | +config VIRTIOGL | |
16 | + tristate "Virtio userspace memory transport" | |
17 | + depends on VIRTIO_PCI | |
18 | + default n | |
19 | + help | |
20 | + A Driver to facilitate transferring data from userspace to a | |
21 | + hypervisor (eg. qemu) | |
22 | + | |
23 | diff --git a/drivers/gpu/misc/Makefile b/drivers/gpu/misc/Makefile | |
24 | new file mode 100644 | |
25 | index 0000000..d9ab333 | |
26 | --- /dev/null | |
27 | +++ b/drivers/gpu/misc/Makefile | |
28 | @@ -0,0 +1 @@ | |
29 | +obj-$(CONFIG_VIRTIOGL) += virtio-gl.o | |
30 | diff --git a/drivers/gpu/misc/virtio-gl.c b/drivers/gpu/misc/virtio-gl.c | |
31 | new file mode 100644 | |
32 | index 0000000..8882bda | |
33 | --- /dev/null | |
34 | +++ b/drivers/gpu/misc/virtio-gl.c | |
35 | @@ -0,0 +1,312 @@ | |
36 | +/* | |
37 | + * Copyright (C) 2010 Intel Corporation | |
38 | + * | |
39 | + * Author: Ian Molton <ian.molton@collabora.co.uk> | |
40 | + * | |
41 | + * This program is free software; you can redistribute it and/or modify | |
42 | + * it under the terms of the GNU General Public License as published by | |
43 | + * the Free Software Foundation; either version 2 of the License, or | |
44 | + * (at your option) any later version. | |
45 | + * | |
46 | + * This program is distributed in the hope that it will be useful, | |
47 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
48 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
49 | + * GNU General Public License for more details. | |
50 | + * | |
51 | + * You should have received a copy of the GNU General Public License | |
52 | + * along with this program; if not, write to the Free Software | |
53 | + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | |
54 | + */ | |
55 | + | |
56 | +#include <linux/kernel.h> | |
57 | +#include <linux/module.h> | |
58 | +#include <linux/fs.h> | |
59 | +#include <linux/dma-mapping.h> | |
60 | +#include <linux/sched.h> | |
61 | +#include <linux/slab.h> | |
62 | +#include <linux/miscdevice.h> | |
63 | +#include <linux/virtio.h> | |
64 | +#include <linux/virtio_ids.h> | |
65 | +#include <linux/virtio_config.h> | |
66 | + | |
67 | +#define DEVICE_NAME "glmem" | |
68 | + | |
69 | +/* Define to use debugging checksums on transfers */ | |
70 | +#undef DEBUG_GLIO | |
71 | + | |
72 | +struct virtio_gl_data { | |
73 | + char *buffer; | |
74 | + int pages; | |
75 | + unsigned int pid; | |
76 | +}; | |
77 | + | |
78 | +struct virtio_gl_header { | |
79 | + int pid; | |
80 | + int buf_size; | |
81 | + int r_buf_size; | |
82 | +#ifdef DEBUG_GLIO | |
83 | + int sum; | |
84 | +#endif | |
85 | + char buffer; | |
86 | +} __packed; | |
87 | + | |
88 | +#define to_virtio_gl_data(a) ((struct virtio_gl_data *)(a)->private_data) | |
89 | + | |
90 | +#ifdef DEBUG_GLIO | |
91 | +#define SIZE_OUT_HEADER (sizeof(int)*4) | |
92 | +#define SIZE_IN_HEADER (sizeof(int)*2) | |
93 | +#else | |
94 | +#define SIZE_OUT_HEADER (sizeof(int)*3) | |
95 | +#define SIZE_IN_HEADER sizeof(int) | |
96 | +#endif | |
97 | + | |
98 | +static struct virtqueue *vq; | |
99 | + | |
100 | + | |
101 | +/* This is videobuf_vmalloc_to_sg() from videobuf-dma-sg.c with | |
102 | + * some modifications | |
103 | + */ | |
104 | +static struct scatterlist *vmalloc_to_sg(struct scatterlist *sg_list, | |
105 | + unsigned char *virt, unsigned int pages) | |
106 | +{ | |
107 | + struct page *pg; | |
108 | + | |
109 | + /* unaligned */ | |
110 | + BUG_ON((ulong)virt & ~PAGE_MASK); | |
111 | + | |
112 | + /* Fill with elements for the data */ | |
113 | + while (pages) { | |
114 | + pg = vmalloc_to_page(virt); | |
115 | + if (!pg) | |
116 | + goto err; | |
117 | + | |
118 | + sg_set_page(sg_list, pg, PAGE_SIZE, 0); | |
119 | + virt += PAGE_SIZE; | |
120 | + sg_list++; | |
121 | + pages--; | |
122 | + } | |
123 | + | |
124 | + return sg_list; | |
125 | + | |
126 | +err: | |
127 | + kfree(sg_list); | |
128 | + return NULL; | |
129 | +} | |
130 | + | |
131 | +static int put_data(struct virtio_gl_data *gldata) | |
132 | +{ | |
133 | + struct scatterlist *sg, *sg_list; | |
134 | + unsigned int count, ret, o_page, i_page, sg_entries; | |
135 | + struct virtio_gl_header *header = | |
136 | + (struct virtio_gl_header *)gldata->buffer; | |
137 | + | |
138 | + ret = header->buf_size; | |
139 | + | |
140 | + o_page = (header->buf_size + PAGE_SIZE-1) >> PAGE_SHIFT; | |
141 | + i_page = (header->r_buf_size + PAGE_SIZE-1) >> PAGE_SHIFT; | |
142 | + | |
143 | + header->pid = gldata->pid; | |
144 | + | |
145 | + if ((o_page && i_page) && | |
146 | + (o_page > gldata->pages || i_page > gldata->pages)) { | |
147 | + i_page = 0; | |
148 | + } | |
149 | + | |
150 | + if (o_page > gldata->pages) | |
151 | + o_page = gldata->pages; | |
152 | + | |
153 | + if (i_page > gldata->pages) | |
154 | + i_page = gldata->pages; | |
155 | + | |
156 | + if (!o_page) | |
157 | + o_page = 1; | |
158 | + | |
159 | + sg_entries = o_page + i_page; | |
160 | + | |
161 | + sg_list = kcalloc(sg_entries, sizeof(struct scatterlist), GFP_KERNEL); | |
162 | + | |
163 | + if (!sg_list) { | |
164 | + ret = -EIO; | |
165 | + goto out; | |
166 | + } | |
167 | + | |
168 | + sg_init_table(sg_list, sg_entries); | |
169 | + | |
170 | + sg = vmalloc_to_sg(sg_list, gldata->buffer, o_page); | |
171 | + sg = vmalloc_to_sg(sg, gldata->buffer, i_page); | |
172 | + | |
173 | + if (!sg) { | |
174 | + ret = -EIO; | |
175 | + goto out_free; | |
176 | + } | |
177 | + | |
178 | + /* Transfer data */ | |
7eafdf33 | 179 | + if (virtqueue_add_buf(vq, sg_list, o_page, i_page, (void *)1, GFP_ATOMIC) >= 0) { |
af0f7570 KK |
180 | + virtqueue_kick(vq); |
181 | + /* Chill out until it's done with the buffer. */ | |
182 | + while (!virtqueue_get_buf(vq, &count)) | |
183 | + cpu_relax(); | |
184 | + } | |
185 | + | |
186 | +out_free: | |
187 | + kfree(sg_list); | |
188 | +out: | |
189 | + return ret; | |
190 | +} | |
191 | + | |
192 | +static void free_buffer(struct virtio_gl_data *gldata) | |
193 | +{ | |
194 | + if (gldata->buffer) { | |
195 | + vfree(gldata->buffer); | |
196 | + gldata->buffer = NULL; | |
197 | + } | |
198 | +} | |
199 | + | |
200 | +static int glmem_open(struct inode *inode, struct file *file) | |
201 | +{ | |
202 | + struct virtio_gl_data *gldata = kzalloc(sizeof(struct virtio_gl_data), | |
203 | + GFP_KERNEL); | |
204 | + | |
205 | + if (!gldata) | |
206 | + return -ENXIO; | |
207 | + | |
208 | + gldata->pid = pid_nr(task_pid(current)); | |
209 | + | |
210 | + file->private_data = gldata; | |
211 | + | |
212 | + return 0; | |
213 | +} | |
214 | + | |
215 | +static int glmem_mmap(struct file *filp, struct vm_area_struct *vma) | |
216 | +{ | |
217 | + struct virtio_gl_data *gldata = to_virtio_gl_data(filp); | |
218 | + int pages = (vma->vm_end - vma->vm_start) / PAGE_SIZE; | |
219 | + | |
220 | + /* Set a reasonable limit */ | |
221 | + if (pages > 16) | |
222 | + return -ENOMEM; | |
223 | + | |
224 | + /* for now, just allow one buffer to be mmap()ed. */ | |
225 | + if (gldata->buffer) | |
226 | + return -EIO; | |
227 | + | |
228 | + gldata->buffer = vmalloc_user(pages*PAGE_SIZE); | |
229 | + | |
230 | + if (!gldata->buffer) | |
231 | + return -ENOMEM; | |
232 | + | |
233 | + gldata->pages = pages; | |
234 | + | |
235 | + if (remap_vmalloc_range(vma, gldata->buffer, 0) < 0) { | |
236 | + vfree(gldata->buffer); | |
237 | + return -EIO; | |
238 | + } | |
239 | + | |
240 | + vma->vm_flags |= VM_DONTEXPAND; | |
241 | + | |
242 | + return 0; | |
243 | +} | |
244 | + | |
245 | +static int glmem_fsync(struct file *filp, int datasync) | |
246 | +{ | |
247 | + struct virtio_gl_data *gldata = to_virtio_gl_data(filp); | |
248 | + | |
249 | + put_data(gldata); | |
250 | + | |
251 | + return 0; | |
252 | +} | |
253 | + | |
254 | +static int glmem_release(struct inode *inode, struct file *file) | |
255 | +{ | |
256 | + struct virtio_gl_data *gldata = to_virtio_gl_data(file); | |
257 | + | |
258 | + if (gldata && gldata->buffer) { | |
259 | + struct virtio_gl_header *header = | |
260 | + (struct virtio_gl_header *)gldata->buffer; | |
261 | + | |
262 | + /* Make sure the host hears about the process ending / dying */ | |
263 | + header->pid = gldata->pid; | |
264 | + header->buf_size = SIZE_OUT_HEADER + 2; | |
265 | + header->r_buf_size = SIZE_IN_HEADER; | |
266 | + *(short *)(&header->buffer) = -1; | |
267 | + | |
268 | + put_data(gldata); | |
269 | + free_buffer(gldata); | |
270 | + } | |
271 | + | |
272 | + kfree(gldata); | |
273 | + | |
274 | + return 0; | |
275 | +} | |
276 | + | |
277 | +static const struct file_operations glmem_fops = { | |
278 | + .owner = THIS_MODULE, | |
279 | + .open = glmem_open, | |
280 | + .mmap = glmem_mmap, | |
281 | + .fsync = glmem_fsync, | |
282 | + .release = glmem_release, | |
283 | +}; | |
284 | + | |
285 | +static struct miscdevice glmem_dev = { | |
286 | + MISC_DYNAMIC_MINOR, | |
287 | + DEVICE_NAME, | |
288 | + &glmem_fops | |
289 | +}; | |
290 | + | |
291 | +static int glmem_probe(struct virtio_device *vdev) | |
292 | +{ | |
293 | + int ret; | |
294 | + | |
295 | + /* We expect a single virtqueue. */ | |
296 | + vq = virtio_find_single_vq(vdev, NULL, "output"); | |
297 | + if (IS_ERR(vq)) | |
298 | + return PTR_ERR(vq); | |
299 | + | |
300 | + ret = misc_register(&glmem_dev); | |
301 | + if (ret) { | |
302 | + printk(KERN_ERR "glmem: cannot register glmem_dev as misc"); | |
303 | + return -ENODEV; | |
304 | + } | |
305 | + | |
306 | + return 0; | |
307 | +} | |
308 | + | |
309 | +static void __devexit glmem_remove(struct virtio_device *vdev) | |
310 | +{ | |
311 | + vdev->config->reset(vdev); | |
312 | + misc_deregister(&glmem_dev); | |
313 | + vdev->config->del_vqs(vdev); | |
314 | +} | |
315 | + | |
316 | +static struct virtio_device_id id_table[] = { | |
317 | + { VIRTIO_ID_GL, VIRTIO_DEV_ANY_ID }, | |
318 | + { 0 }, | |
319 | +}; | |
320 | + | |
321 | +static struct virtio_driver virtio_gl_driver = { | |
322 | + .driver = { | |
323 | + .name = KBUILD_MODNAME, | |
324 | + .owner = THIS_MODULE, | |
325 | + }, | |
326 | + .id_table = id_table, | |
327 | + .probe = glmem_probe, | |
328 | + .remove = __devexit_p(glmem_remove), | |
329 | +}; | |
330 | + | |
331 | +static int __init glmem_init(void) | |
332 | +{ | |
333 | + return register_virtio_driver(&virtio_gl_driver); | |
334 | +} | |
335 | + | |
336 | +static void __exit glmem_exit(void) | |
337 | +{ | |
338 | + unregister_virtio_driver(&virtio_gl_driver); | |
339 | +} | |
340 | + | |
341 | +module_init(glmem_init); | |
342 | +module_exit(glmem_exit); | |
343 | + | |
344 | +MODULE_DEVICE_TABLE(virtio, id_table); | |
345 | +MODULE_DESCRIPTION("Virtio gl passthrough driver"); | |
346 | +MODULE_LICENSE("GPL v2"); | |
347 | + | |
348 | diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig | |
349 | index 3d94a14..9a9a6cc 100644 | |
350 | --- a/drivers/video/Kconfig | |
351 | +++ b/drivers/video/Kconfig | |
352 | @@ -16,6 +16,7 @@ source "drivers/char/agp/Kconfig" | |
353 | source "drivers/gpu/vga/Kconfig" | |
354 | ||
355 | source "drivers/gpu/drm/Kconfig" | |
356 | +source "drivers/gpu/misc/Kconfig" | |
357 | ||
358 | config VGASTATE | |
359 | tristate | |
537831f9 AM |
360 | --- linux-3.4/include/uapi/linux/virtio_ids.h~ 2012-05-21 08:42:02.000000000 +0200 |
361 | +++ linux-3.4/include/uapi/linux/virtio_ids.h 2012-05-21 09:02:40.065957644 +0200 | |
92d182d2 | 362 | @@ -34,6 +34,7 @@ |
af0f7570 KK |
363 | #define VIRTIO_ID_CONSOLE 3 /* virtio console */ |
364 | #define VIRTIO_ID_RNG 4 /* virtio ring */ | |
365 | #define VIRTIO_ID_BALLOON 5 /* virtio balloon */ | |
366 | +#define VIRTIO_ID_GL 6 /* virtio usermem */ | |
92d182d2 AM |
367 | #define VIRTIO_ID_RPMSG 7 /* virtio remote processor messaging */ |
368 | #define VIRTIO_ID_SCSI 8 /* virtio scsi */ | |
af0f7570 | 369 | #define VIRTIO_ID_9P 9 /* 9p virtio console */ |
af0f7570 | 370 |