]> git.pld-linux.org Git - packages/kernel.git/blame - kernel-virtio-gl-accel.patch
- 4.4.126
[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
392086de 35@@ -0,0 +1,315 @@
af0f7570
KK
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+ */
af0f7570
KK
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>
c2c0f25c 62+#include <linux/vmalloc.h>
af0f7570
KK
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 */
392086de
AM
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) {
af0f7570
KK
183+ virtqueue_kick(vq);
184+ /* Chill out until it's done with the buffer. */
185+ while (!virtqueue_get_buf(vq, &count))
186+ cpu_relax();
187+ }
188+
189+out_free:
190+ kfree(sg_list);
191+out:
192+ return ret;
193+}
194+
195+static void free_buffer(struct virtio_gl_data *gldata)
196+{
197+ if (gldata->buffer) {
198+ vfree(gldata->buffer);
199+ gldata->buffer = NULL;
200+ }
201+}
202+
203+static int glmem_open(struct inode *inode, struct file *file)
204+{
205+ struct virtio_gl_data *gldata = kzalloc(sizeof(struct virtio_gl_data),
206+ GFP_KERNEL);
207+
208+ if (!gldata)
209+ return -ENXIO;
210+
211+ gldata->pid = pid_nr(task_pid(current));
212+
213+ file->private_data = gldata;
214+
215+ return 0;
216+}
217+
218+static int glmem_mmap(struct file *filp, struct vm_area_struct *vma)
219+{
220+ struct virtio_gl_data *gldata = to_virtio_gl_data(filp);
221+ int pages = (vma->vm_end - vma->vm_start) / PAGE_SIZE;
222+
223+ /* Set a reasonable limit */
224+ if (pages > 16)
225+ return -ENOMEM;
226+
227+ /* for now, just allow one buffer to be mmap()ed. */
228+ if (gldata->buffer)
229+ return -EIO;
230+
231+ gldata->buffer = vmalloc_user(pages*PAGE_SIZE);
232+
233+ if (!gldata->buffer)
234+ return -ENOMEM;
235+
236+ gldata->pages = pages;
237+
238+ if (remap_vmalloc_range(vma, gldata->buffer, 0) < 0) {
239+ vfree(gldata->buffer);
240+ return -EIO;
241+ }
242+
243+ vma->vm_flags |= VM_DONTEXPAND;
244+
245+ return 0;
246+}
247+
7c99cdc1 248+static int glmem_fsync(struct file *filp, loff_t unused1, loff_t unused2, int datasync)
af0f7570
KK
249+{
250+ struct virtio_gl_data *gldata = to_virtio_gl_data(filp);
251+
252+ put_data(gldata);
253+
254+ return 0;
255+}
256+
257+static int glmem_release(struct inode *inode, struct file *file)
258+{
259+ struct virtio_gl_data *gldata = to_virtio_gl_data(file);
260+
261+ if (gldata && gldata->buffer) {
262+ struct virtio_gl_header *header =
263+ (struct virtio_gl_header *)gldata->buffer;
264+
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;
270+
271+ put_data(gldata);
272+ free_buffer(gldata);
273+ }
274+
275+ kfree(gldata);
276+
277+ return 0;
278+}
279+
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,
286+};
287+
288+static struct miscdevice glmem_dev = {
289+ MISC_DYNAMIC_MINOR,
290+ DEVICE_NAME,
291+ &glmem_fops
292+};
293+
294+static int glmem_probe(struct virtio_device *vdev)
295+{
296+ int ret;
297+
298+ /* We expect a single virtqueue. */
299+ vq = virtio_find_single_vq(vdev, NULL, "output");
300+ if (IS_ERR(vq))
301+ return PTR_ERR(vq);
302+
303+ ret = misc_register(&glmem_dev);
304+ if (ret) {
305+ printk(KERN_ERR "glmem: cannot register glmem_dev as misc");
306+ return -ENODEV;
307+ }
308+
309+ return 0;
310+}
311+
1716fcea 312+static void glmem_remove(struct virtio_device *vdev)
af0f7570
KK
313+{
314+ vdev->config->reset(vdev);
315+ misc_deregister(&glmem_dev);
316+ vdev->config->del_vqs(vdev);
317+}
318+
319+static struct virtio_device_id id_table[] = {
320+ { VIRTIO_ID_GL, VIRTIO_DEV_ANY_ID },
321+ { 0 },
322+};
323+
324+static struct virtio_driver virtio_gl_driver = {
325+ .driver = {
326+ .name = KBUILD_MODNAME,
327+ .owner = THIS_MODULE,
328+ },
329+ .id_table = id_table,
330+ .probe = glmem_probe,
1716fcea 331+ .remove = glmem_remove,
af0f7570
KK
332+};
333+
334+static int __init glmem_init(void)
335+{
336+ return register_virtio_driver(&virtio_gl_driver);
337+}
338+
339+static void __exit glmem_exit(void)
340+{
341+ unregister_virtio_driver(&virtio_gl_driver);
342+}
343+
344+module_init(glmem_init);
345+module_exit(glmem_exit);
346+
347+MODULE_DEVICE_TABLE(virtio, id_table);
348+MODULE_DESCRIPTION("Virtio gl passthrough driver");
349+MODULE_LICENSE("GPL v2");
350+
351diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig
352index 3d94a14..9a9a6cc 100644
353--- a/drivers/video/Kconfig
354+++ b/drivers/video/Kconfig
355@@ -16,6 +16,7 @@ source "drivers/char/agp/Kconfig"
ea0aec88 356 endmenu
af0f7570 357
ea0aec88 358 source "drivers/video/backlight/Kconfig"
af0f7570
KK
359+source "drivers/gpu/misc/Kconfig"
360
361 config VGASTATE
362 tristate
537831f9
AM
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
92d182d2 365@@ -34,6 +34,7 @@
af0f7570
KK
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 */
92d182d2
AM
370 #define VIRTIO_ID_RPMSG 7 /* virtio remote processor messaging */
371 #define VIRTIO_ID_SCSI 8 /* virtio scsi */
af0f7570 372 #define VIRTIO_ID_9P 9 /* 9p virtio console */
af0f7570 373
This page took 1.863512 seconds and 4 git commands to generate.