]> git.pld-linux.org Git - packages/kernel.git/blame - kernel-virtio-gl-accel.patch
- 3.1.101
[packages/kernel.git] / kernel-virtio-gl-accel.patch
CommitLineData
7eafdf33 1M/
af0f7570
KK
2diff --git a/drivers/gpu/Makefile b/drivers/gpu/Makefile
3index 30879df..35699a0 100644
4--- a/drivers/gpu/Makefile
5+++ b/drivers/gpu/Makefile
6@@ -1 +1 @@
514e5dae
AM
7-obj-y += drm/ vga/
8+obj-y += drm/ vga/ misc/
af0f7570
KK
9diff --git a/drivers/gpu/misc/Kconfig b/drivers/gpu/misc/Kconfig
10new file mode 100644
11index 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+
23diff --git a/drivers/gpu/misc/Makefile b/drivers/gpu/misc/Makefile
24new file mode 100644
25index 0000000..d9ab333
26--- /dev/null
27+++ b/drivers/gpu/misc/Makefile
28@@ -0,0 +1 @@
29+obj-$(CONFIG_VIRTIOGL) += virtio-gl.o
30diff --git a/drivers/gpu/misc/virtio-gl.c b/drivers/gpu/misc/virtio-gl.c
31new file mode 100644
32index 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+
1716fcea 309+static void glmem_remove(struct virtio_device *vdev)
af0f7570
KK
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,
1716fcea 328+ .remove = glmem_remove,
af0f7570
KK
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+
348diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig
349index 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
This page took 0.122606 seconds and 4 git commands to generate.