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
8 +obj-y += drm/ vga/ misc/
9 diff --git a/drivers/gpu/misc/Kconfig b/drivers/gpu/misc/Kconfig
11 index 0000000..50043d3
13 +++ b/drivers/gpu/misc/Kconfig
16 + tristate "Virtio userspace memory transport"
17 + depends on VIRTIO_PCI
20 + A Driver to facilitate transferring data from userspace to a
21 + hypervisor (eg. qemu)
23 diff --git a/drivers/gpu/misc/Makefile b/drivers/gpu/misc/Makefile
25 index 0000000..d9ab333
27 +++ b/drivers/gpu/misc/Makefile
29 +obj-$(CONFIG_VIRTIOGL) += virtio-gl.o
30 diff --git a/drivers/gpu/misc/virtio-gl.c b/drivers/gpu/misc/virtio-gl.c
32 index 0000000..8882bda
34 +++ b/drivers/gpu/misc/virtio-gl.c
37 + * Copyright (C) 2010 Intel Corporation
39 + * Author: Ian Molton <ian.molton@collabora.co.uk>
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.
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.
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
55 +#include <linux/kernel.h>
56 +#include <linux/module.h>
57 +#include <linux/fs.h>
58 +#include <linux/dma-mapping.h>
59 +#include <linux/sched.h>
60 +#include <linux/slab.h>
61 +#include <linux/miscdevice.h>
62 +#include <linux/vmalloc.h>
63 +#include <linux/virtio.h>
64 +#include <linux/virtio_ids.h>
65 +#include <linux/virtio_config.h>
67 +#define DEVICE_NAME "glmem"
69 +/* Define to use debugging checksums on transfers */
72 +struct virtio_gl_data {
78 +struct virtio_gl_header {
88 +#define to_virtio_gl_data(a) ((struct virtio_gl_data *)(a)->private_data)
91 +#define SIZE_OUT_HEADER (sizeof(int)*4)
92 +#define SIZE_IN_HEADER (sizeof(int)*2)
94 +#define SIZE_OUT_HEADER (sizeof(int)*3)
95 +#define SIZE_IN_HEADER sizeof(int)
98 +static struct virtqueue *vq;
101 +/* This is videobuf_vmalloc_to_sg() from videobuf-dma-sg.c with
102 + * some modifications
104 +static struct scatterlist *vmalloc_to_sg(struct scatterlist *sg_list,
105 + unsigned char *virt, unsigned int pages)
110 + BUG_ON((ulong)virt & ~PAGE_MASK);
112 + /* Fill with elements for the data */
114 + pg = vmalloc_to_page(virt);
118 + sg_set_page(sg_list, pg, PAGE_SIZE, 0);
131 +static int put_data(struct virtio_gl_data *gldata)
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;
138 + ret = header->buf_size;
140 + o_page = (header->buf_size + PAGE_SIZE-1) >> PAGE_SHIFT;
141 + i_page = (header->r_buf_size + PAGE_SIZE-1) >> PAGE_SHIFT;
143 + header->pid = gldata->pid;
145 + if ((o_page && i_page) &&
146 + (o_page > gldata->pages || i_page > gldata->pages)) {
150 + if (o_page > gldata->pages)
151 + o_page = gldata->pages;
153 + if (i_page > gldata->pages)
154 + i_page = gldata->pages;
159 + sg_entries = o_page + i_page;
161 + sg_list = kcalloc(sg_entries, sizeof(struct scatterlist), GFP_KERNEL);
168 + sg_init_table(sg_list, sg_entries);
170 + sg = vmalloc_to_sg(sg_list, gldata->buffer, o_page);
171 + sg = vmalloc_to_sg(sg, gldata->buffer, i_page);
178 + /* Transfer data */
179 + struct scatterlist *sgs[2];
180 + sgs[0] = &sg_list[0];
181 + sgs[1] = &sg_list[1];
182 + if (virtqueue_add_sgs(vq, sgs, o_page, i_page, (void *)1, GFP_ATOMIC) >= 0) {
183 + virtqueue_kick(vq);
184 + /* Chill out until it's done with the buffer. */
185 + while (!virtqueue_get_buf(vq, &count))
195 +static void free_buffer(struct virtio_gl_data *gldata)
197 + if (gldata->buffer) {
198 + vfree(gldata->buffer);
199 + gldata->buffer = NULL;
203 +static int glmem_open(struct inode *inode, struct file *file)
205 + struct virtio_gl_data *gldata = kzalloc(sizeof(struct virtio_gl_data),
211 + gldata->pid = pid_nr(task_pid(current));
213 + file->private_data = gldata;
218 +static int glmem_mmap(struct file *filp, struct vm_area_struct *vma)
220 + struct virtio_gl_data *gldata = to_virtio_gl_data(filp);
221 + int pages = (vma->vm_end - vma->vm_start) / PAGE_SIZE;
223 + /* Set a reasonable limit */
227 + /* for now, just allow one buffer to be mmap()ed. */
228 + if (gldata->buffer)
231 + gldata->buffer = vmalloc_user(pages*PAGE_SIZE);
233 + if (!gldata->buffer)
236 + gldata->pages = pages;
238 + if (remap_vmalloc_range(vma, gldata->buffer, 0) < 0) {
239 + vfree(gldata->buffer);
243 + vma->vm_flags |= VM_DONTEXPAND;
248 +static int glmem_fsync(struct file *filp, int datasync)
250 + struct virtio_gl_data *gldata = to_virtio_gl_data(filp);
257 +static int glmem_release(struct inode *inode, struct file *file)
259 + struct virtio_gl_data *gldata = to_virtio_gl_data(file);
261 + if (gldata && gldata->buffer) {
262 + struct virtio_gl_header *header =
263 + (struct virtio_gl_header *)gldata->buffer;
265 + /* Make sure the host hears about the process ending / dying */
266 + header->pid = gldata->pid;
267 + header->buf_size = SIZE_OUT_HEADER + 2;
268 + header->r_buf_size = SIZE_IN_HEADER;
269 + *(short *)(&header->buffer) = -1;
272 + free_buffer(gldata);
280 +static const struct file_operations glmem_fops = {
281 + .owner = THIS_MODULE,
282 + .open = glmem_open,
283 + .mmap = glmem_mmap,
284 + .fsync = glmem_fsync,
285 + .release = glmem_release,
288 +static struct miscdevice glmem_dev = {
289 + MISC_DYNAMIC_MINOR,
294 +static int glmem_probe(struct virtio_device *vdev)
298 + /* We expect a single virtqueue. */
299 + vq = virtio_find_single_vq(vdev, NULL, "output");
301 + return PTR_ERR(vq);
303 + ret = misc_register(&glmem_dev);
305 + printk(KERN_ERR "glmem: cannot register glmem_dev as misc");
312 +static void glmem_remove(struct virtio_device *vdev)
314 + vdev->config->reset(vdev);
315 + misc_deregister(&glmem_dev);
316 + vdev->config->del_vqs(vdev);
319 +static struct virtio_device_id id_table[] = {
320 + { VIRTIO_ID_GL, VIRTIO_DEV_ANY_ID },
324 +static struct virtio_driver virtio_gl_driver = {
326 + .name = KBUILD_MODNAME,
327 + .owner = THIS_MODULE,
329 + .id_table = id_table,
330 + .probe = glmem_probe,
331 + .remove = glmem_remove,
334 +static int __init glmem_init(void)
336 + return register_virtio_driver(&virtio_gl_driver);
339 +static void __exit glmem_exit(void)
341 + unregister_virtio_driver(&virtio_gl_driver);
344 +module_init(glmem_init);
345 +module_exit(glmem_exit);
347 +MODULE_DEVICE_TABLE(virtio, id_table);
348 +MODULE_DESCRIPTION("Virtio gl passthrough driver");
349 +MODULE_LICENSE("GPL v2");
351 diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig
352 index 3d94a14..9a9a6cc 100644
353 --- a/drivers/video/Kconfig
354 +++ b/drivers/video/Kconfig
355 @@ -16,6 +16,7 @@ source "drivers/char/agp/Kconfig"
358 source "drivers/video/backlight/Kconfig"
359 +source "drivers/gpu/misc/Kconfig"
363 --- linux-3.4/include/uapi/linux/virtio_ids.h~ 2012-05-21 08:42:02.000000000 +0200
364 +++ linux-3.4/include/uapi/linux/virtio_ids.h 2012-05-21 09:02:40.065957644 +0200
366 #define VIRTIO_ID_CONSOLE 3 /* virtio console */
367 #define VIRTIO_ID_RNG 4 /* virtio ring */
368 #define VIRTIO_ID_BALLOON 5 /* virtio balloon */
369 +#define VIRTIO_ID_GL 6 /* virtio usermem */
370 #define VIRTIO_ID_RPMSG 7 /* virtio remote processor messaging */
371 #define VIRTIO_ID_SCSI 8 /* virtio scsi */
372 #define VIRTIO_ID_9P 9 /* 9p virtio console */