YaGL: Transport improved
authorStanislav Vorobiov <s.vorobiov@samsung.com>
Tue, 24 Sep 2013 14:48:33 +0000 (18:48 +0400)
committerSeokYeon Hwang <syeon.hwang@samsung.com>
Wed, 9 Apr 2014 05:42:27 +0000 (14:42 +0900)
The improvements are:

* No more mlock/munlock. We now have ioctls for locking drawable
  memory so that compile transfers could be created on host. This
  is only used by offscreen backend though
* We're now using a single buffer for marshalling instead of two: one
  for commands and one for data. Also, the buffer can now be of any
  size up to 2M, it's implemented as a page list, thus, we don't need
  to allocate contigous memory anymore

Change-Id: Ia9b716c9135df75535dc515367550c9fbcf9c737

drivers/gpu/yagl/Kconfig
drivers/gpu/yagl/Makefile
drivers/gpu/yagl/yagl_driver.c
drivers/gpu/yagl/yagl_ioctl.h [new file with mode: 0644]
drivers/gpu/yagl/yagl_marshal.h [deleted file]
drivers/gpu/yagl/yagl_version.h [deleted file]

index efb06f4..88e48db 100644 (file)
@@ -3,7 +3,7 @@
 #
 
 menuconfig YAGL
-       bool "YaGL passthrough driver"
+       tristate "YaGL passthrough driver"
        depends on (DRM || FB)
        default n
        help
index 74e1836..5d1a93a 100644 (file)
@@ -4,4 +4,6 @@
 
 ccflags-y := -Idrivers/gpu/yagl
 
-obj-$(CONFIG_YAGL) += main.o yagl_driver.o
+yagl-y := main.o yagl_driver.o
+
+obj-$(CONFIG_YAGL) += yagl.o
index 90743c5..1bb7261 100644 (file)
@@ -1,6 +1,5 @@
 #include "yagl_driver.h"
-#include "yagl_marshal.h"
-#include "yagl_version.h"
+#include "yagl_ioctl.h"
 #include "yagl.h"
 #include "debug.h"
 #include "print.h"
@@ -16,6 +15,7 @@
 #include <linux/miscdevice.h>
 #include <linux/uaccess.h>
 #include <linux/pci.h>
+#include <linux/pagemap.h>
 
 #define YAGL_REG_BUFFPTR 0
 #define YAGL_REG_TRIGGER 4
@@ -61,6 +61,16 @@ struct yagl_device
     struct mutex mutex;
 };
 
+struct yagl_mlock
+{
+    struct list_head list;
+
+    unsigned long address;
+
+    struct page **pages;
+    u32 num_pages;
+};
+
 struct yagl_file
 {
     /* Owning device */
@@ -69,16 +79,46 @@ struct yagl_file
     /* Index in 'user_map', filled on 'open' */
     int index;
 
-    /* Buffer used for marshalling, allocated in mmap */
-    u8 *buff;
+    /* Pages of a buffer. */
+    struct page **pages;
+    u32 num_pages;
+
+    /* Render type for this client, filled on 'open'. */
+    u32 render_type;
 
-    /* Buffer size */
-    unsigned long buff_size;
+    /* List of mlock'ed memory regions. */
+    struct list_head mlock_list;
 };
 
-static void yagl_user_activate(void __iomem *regs,
-                               int index,
-                               unsigned long buff_pa)
+static __inline void yagl_marshal_put_uint32_t(u8** buff, u32 value)
+{
+    *(u32*)(*buff) = value;
+    *buff += 8;
+}
+
+static __inline u32 yagl_marshal_get_uint32_t(u8** buff)
+{
+    u32 tmp = *(u32*)*buff;
+    *buff += 8;
+    return tmp;
+}
+
+static void yagl_marshal_put_page_list(u8 **buff,
+                                       struct page **pages,
+                                       u32 count)
+{
+    u32 i;
+
+    yagl_marshal_put_uint32_t(buff, count);
+
+    for (i = 0; i < count; ++i) {
+        yagl_marshal_put_uint32_t(buff, (uint32_t)page_to_phys(pages[i]));
+    }
+}
+
+static void yagl_user_activate_update(void __iomem *regs,
+                                      int index,
+                                      unsigned long buff_pa)
 {
     writel(buff_pa, YAGL_USER_PTR(regs, index) + YAGL_REG_BUFFPTR);
 }
@@ -88,29 +128,87 @@ static void yagl_user_deactivate(void __iomem *regs, int index)
     writel(0, YAGL_USER_PTR(regs, index) + YAGL_REG_BUFFPTR);
 }
 
+static int yagl_alloc_pages(struct page ***pages,
+                            u32 num_present,
+                            u32 num_alloc)
+{
+    struct page **tmp;
+    int ret = 0, i;
+
+    tmp = kzalloc((num_present + num_alloc) * sizeof(*tmp), GFP_KERNEL);
+
+    if (!tmp) {
+        dprintk("unable to allocate memory\n");
+        ret = -ENOMEM;
+        goto fail1;
+    }
+
+    for (i = 0; i < (int)num_alloc; ++i) {
+        tmp[num_present + i] = alloc_page(GFP_KERNEL | __GFP_HIGHMEM);
+        if (!tmp[num_present + i]) {
+            dprintk("unable to allocate page\n");
+            ret = -ENOMEM;
+            goto fail2;
+        }
+    }
+
+    if (num_present > 0) {
+        memcpy(tmp, *pages, num_present * sizeof(*tmp));
+        kfree(*pages);
+    }
+
+    *pages = tmp;
+
+    return 0;
+
+fail2:
+    while (--i >= 0) {
+        __free_page(tmp[num_present + i]);
+    }
+    kfree(tmp);
+fail1:
+    return ret;
+}
+
+static void yagl_put_pages(struct page ***pages, u32 num_present, u32 num_put)
+{
+    u32 i;
+
+    for (i = 1; i <= num_put; ++i) {
+        __free_page((*pages)[num_present - i]);
+    }
+
+    if (num_present == num_put) {
+        kfree(*pages);
+        *pages = NULL;
+    }
+}
+
 static int yagl_misc_open(struct inode *inode, struct file *file)
 {
     int ret = 0;
-    struct yagl_device *device = container_of( file->private_data,
-                                               struct yagl_device,
-                                               miscdev );
-
+    struct yagl_device *device = container_of(file->private_data,
+                                              struct yagl_device,
+                                              miscdev);
     struct yagl_file *yfile;
     int i;
+    u8 *buff;
+    pid_t process_id;
+    pid_t thread_id;
 
     mutex_lock(&device->mutex);
 
     if (file->f_mode & FMODE_EXEC) {
         ret = -EPERM;
-        goto fail;
+        goto fail1;
     }
 
     yfile = kzalloc(sizeof(*yfile), GFP_KERNEL);
 
     if (!yfile) {
-        dprintk("%s: unable to allocate memory\n", device->miscdev.name);
+        dprintk("unable to allocate memory\n");
         ret = -ENOMEM;
-        goto fail;
+        goto fail1;
     }
 
     yfile->device = device;
@@ -125,20 +223,61 @@ static int yagl_misc_open(struct inode *inode, struct file *file)
     }
 
     if (yfile->index == -1) {
-        dprintk("%s: no free slots\n", device->miscdev.name);
+        print_error("no free slots\n");
         ret = -ENOMEM;
-        goto fail;
+        goto fail2;
     }
 
+    yfile->num_pages = 1;
+    ret = yagl_alloc_pages(&yfile->pages, 0, yfile->num_pages);
+
+    if (ret != 0) {
+        goto fail3;
+    }
+
+    buff = kmap(yfile->pages[0]);
+
+    memset(buff, 0, PAGE_SIZE);
+
+    process_id = task_tgid_vnr(current);
+    thread_id = task_pid_vnr(current);
+
+    yagl_marshal_put_uint32_t(&buff, YAGL_VERSION);
+    yagl_marshal_put_uint32_t(&buff, process_id);
+    yagl_marshal_put_uint32_t(&buff, thread_id);
+
+    yagl_user_activate_update(device->regs,
+                              yfile->index,
+                              page_to_phys(yfile->pages[0]));
+
+    if (yagl_marshal_get_uint32_t(&buff) != 1) {
+        ret = -EIO;
+        print_error("unable to init YaGL: probably version mismatch\n");
+        goto fail4;
+    }
+
+    yfile->render_type = yagl_marshal_get_uint32_t(&buff);
+
+    kunmap(yfile->pages[0]);
+
+    INIT_LIST_HEAD(&yfile->mlock_list);
+
     file->private_data = yfile;
 
     mutex_unlock(&device->mutex);
 
-    dprintk("%s: %d opened\n", device->miscdev.name, yfile->index);
+    print_info("%d opened\n", yfile->index);
 
     return nonseekable_open(inode, file);
 
-fail:
+fail4:
+    kunmap(yfile->pages[0]);
+    yagl_put_pages(&yfile->pages, yfile->num_pages, yfile->num_pages);
+fail3:
+    device->user_map[yfile->index] = 0;
+fail2:
+    kfree(yfile);
+fail1:
     mutex_unlock(&device->mutex);
 
     return ret;
@@ -147,25 +286,30 @@ fail:
 static int yagl_misc_release(struct inode *inode, struct file *file)
 {
     struct yagl_file *yfile = file->private_data;
-    int index = yfile->index;
+    struct yagl_mlock *mlock, *tmp;
+    u32 i;
 
     mutex_lock(&yfile->device->mutex);
 
-    yfile->device->user_map[yfile->index] = 0;
-    yfile->index = -1;
+    yagl_user_deactivate(yfile->device->regs, yfile->index);
 
-    if (yfile->buff) {
-        yagl_user_deactivate(yfile->device->regs, index);
+    list_for_each_entry_safe(mlock, tmp, &yfile->mlock_list, list) {
+        for (i = 0; i < mlock->num_pages; ++i) {
+            set_page_dirty_lock(mlock->pages[i]);
+            put_page(mlock->pages[i]);
+        }
+        kfree(mlock->pages);
+        list_del(&mlock->list);
+        kfree(mlock);
+    }
 
-        free_pages((unsigned long)yfile->buff, get_order(yfile->buff_size));
-        yfile->buff = NULL;
+    yagl_put_pages(&yfile->pages, yfile->num_pages, yfile->num_pages);
 
-        dprintk("%s: YaGL exited\n", yfile->device->miscdev.name);
-    }
+    yfile->device->user_map[yfile->index] = 0;
 
     mutex_unlock(&yfile->device->mutex);
 
-    dprintk("%s: %d closed\n", yfile->device->miscdev.name, index);
+    print_info("%d closed\n", yfile->index);
 
     kfree(file->private_data);
     file->private_data = NULL;
@@ -173,147 +317,327 @@ static int yagl_misc_release(struct inode *inode, struct file *file)
     return 0;
 }
 
-static int yagl_misc_mmap(struct file *file, struct vm_area_struct *vma)
+static int yagl_misc_mmap_regs(struct yagl_file *yfile,
+                               struct vm_area_struct *vma)
 {
-    struct yagl_file *yfile = file->private_data;
-    int num_pages = (vma->vm_end - vma->vm_start) / PAGE_SIZE;
     int ret = 0;
-    u8 *buff = NULL;
-    pid_t process_id;
-    pid_t thread_id;
+    u32 num_pages = (vma->vm_end - vma->vm_start) / PAGE_SIZE;
 
-    mutex_lock(&yfile->device->mutex);
+    if (num_pages != 1) {
+        dprintk("%d mmap must be called for 1 page only\n",
+                yfile->index);
+        ret = -EINVAL;
+        goto out;
+    }
 
-    if (vma->vm_pgoff == 0) {
-        /*
-         * First page is 'regs'.
-         */
+    vma->vm_flags |= VM_IO | VM_RESERVED | VM_DONTEXPAND;
+    vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
 
-        if (num_pages != 1) {
-            dprintk("%s: mmap must be called for 1 page only\n",
-                    yfile->device->miscdev.name);
-            ret = -EINVAL;
-            goto out;
-        }
+    ret = remap_pfn_range(vma,
+                          vma->vm_start,
+                          (yfile->device->regs_pa >> PAGE_SHIFT),
+                          num_pages,
+                          vma->vm_page_prot);
 
-        vma->vm_flags |= VM_IO | VM_RESERVED;
-        vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
+    if (ret != 0) {
+        dprintk("%d unable to remap regs memory: %d\n",
+                yfile->index,
+                ret);
+        goto out;
+    }
 
-        ret = remap_pfn_range(vma,
-                              vma->vm_start,
-                              (yfile->device->regs_pa >> PAGE_SHIFT),
-                              num_pages,
-                              vma->vm_page_prot);
+    ret = 0;
 
-        if (ret != 0) {
-            dprintk( "%s: unable to remap regs memory: %d\n",
-                     yfile->device->miscdev.name,
-                     ret );
-            goto out;
-        }
-    } else if (vma->vm_pgoff == 1) {
-        /*
-         * Marshalling buffer.
-         */
+out:
+    return ret;
+}
 
-        int i;
-        unsigned long addr;
-        u32 render_type;
+static int yagl_misc_mmap_buffer(struct yagl_file *yfile,
+                                 struct vm_area_struct *vma)
+{
+    int ret = 0;
+    u32 i, num_pages = (vma->vm_end - vma->vm_start) / PAGE_SIZE;
+    u8 *buff;
+    u32 status;
+    unsigned long addr;
 
-        if (yfile->buff) {
-            dprintk("%s: marshalling buffer already mapped\n",
-                    yfile->device->miscdev.name);
-            ret = -EIO;
-            goto out;
-        }
+    if (num_pages == 0) {
+        dprintk("%d mmap must be called with one page or more\n",
+                yfile->index);
+        return -EINVAL;
+    }
 
-        buff = (u8*)__get_free_pages(GFP_USER|__GFP_COMP,
-                                     get_order(vma->vm_end - vma->vm_start));
+    if (num_pages > ((PAGE_SIZE / 8) - 2)) {
+        dprintk("%d mmap must be called with not more than %ld pages\n",
+                yfile->index,
+                ((PAGE_SIZE / 8) - 2));
+        return -EINVAL;
+    }
 
-        if (!buff) {
-            dprintk("%s: unable to alloc memory\n",
-                    yfile->device->miscdev.name);
-            ret = -ENOMEM;
-            goto out;
-        }
+    if (num_pages != yfile->num_pages) {
+        if (num_pages > yfile->num_pages) {
+            ret = yagl_alloc_pages(&yfile->pages,
+                                   yfile->num_pages,
+                                   (num_pages - yfile->num_pages));
+
+            if (ret != 0) {
+                goto out;
+            }
 
-        vma->vm_flags |= VM_RESERVED | VM_DONTEXPAND;
+            /*
+             * We have at least one new page, use it for page list.
+             */
 
-        addr = vma->vm_start;
+            buff = kmap(yfile->pages[num_pages - 1]);
 
-        for (i = 0; i < num_pages; i++) {
-            ret = vm_insert_page(vma,
-                                 addr,
-                                 virt_to_page((unsigned long)buff + (i * PAGE_SIZE)));
-            if (ret != 0) {
-                dprintk("%s: unable to remap marshalling memory: %d\n",
-                        yfile->device->miscdev.name,
-                        ret );
+            memset(buff, 0, PAGE_SIZE);
+
+            yagl_marshal_put_page_list(&buff, yfile->pages, num_pages);
+
+            yagl_user_activate_update(yfile->device->regs,
+                                      yfile->index,
+                                      page_to_phys(yfile->pages[num_pages - 1]));
+
+            status = yagl_marshal_get_uint32_t(&buff);
+
+            kunmap(yfile->pages[num_pages - 1]);
+
+            if (status != 1) {
+                yagl_put_pages(&yfile->pages,
+                               num_pages,
+                               (num_pages - yfile->num_pages));
+                ret = -EIO;
+                print_error("%d unable to increase YaGL buffer due to host error\n",
+                            yfile->index);
                 goto out;
             }
+        } else {
+            /*
+             * We're putting at least one page, use it for page list before
+             * putting.
+             */
 
-            addr += PAGE_SIZE;
-        }
+            buff = kmap(yfile->pages[yfile->num_pages - 1]);
 
-        yfile->buff = buff;
-        yfile->buff_size = vma->vm_end - vma->vm_start;
+            memset(buff, 0, PAGE_SIZE);
 
-        process_id = task_tgid_vnr(current);
-        thread_id = task_pid_vnr(current);
+            yagl_marshal_put_page_list(&buff, yfile->pages, num_pages);
 
-        yagl_marshal_put_uint32(&buff, YAGL_VERSION);
-        yagl_marshal_put_pid(&buff, process_id);
-        yagl_marshal_put_tid(&buff, thread_id);
+            yagl_user_activate_update(yfile->device->regs,
+                                      yfile->index,
+                                      page_to_phys(yfile->pages[yfile->num_pages - 1]));
 
-        yagl_user_activate(yfile->device->regs,
-                           yfile->index,
-                           virt_to_phys(yfile->buff));
+            status = yagl_marshal_get_uint32_t(&buff);
 
-        buff = yfile->buff;
+            kunmap(yfile->pages[yfile->num_pages - 1]);
 
-        if (yagl_marshal_get_uint32(&buff) != 1)
-        {
-            buff = yfile->buff;
-            yfile->buff = NULL;
-            ret = -EIO;
-            print_error("%s: unable to init YaGL: probably version mismatch\n",
-                        yfile->device->miscdev.name);
+            if (status != 1) {
+                ret = -EIO;
+                print_error("%d unable to decrease YaGL buffer due to host error\n",
+                            yfile->index);
+                goto out;
+            }
+
+            yagl_put_pages(&yfile->pages,
+                           yfile->num_pages,
+                           (yfile->num_pages - num_pages));
+        }
+    }
+
+    yfile->num_pages = num_pages;
+
+    vma->vm_flags |= VM_RESERVED | VM_DONTEXPAND;
+
+    addr = vma->vm_start;
+
+    for (i = 0; i < num_pages; ++i) {
+        ret = vm_insert_page(vma, addr, yfile->pages[i]);
+        if (ret != 0) {
+            dprintk("%d unable to map buffer: %d\n",
+                    yfile->index,
+                    ret);
             goto out;
         }
 
-        render_type = yagl_marshal_get_uint32(&buff);
+        addr += PAGE_SIZE;
+    }
 
-        buff = yfile->buff;
+out:
+    return ret;
+}
 
-        yagl_marshal_put_uint32(&buff, yfile->index);
-        yagl_marshal_put_uint32(&buff, render_type);
+static int yagl_misc_mmap(struct file *file, struct vm_area_struct *vma)
+{
+    struct yagl_file *yfile = file->private_data;
+    int ret = 0;
+
+    dprintk("user = %d, pgoff = %lu, size = %lu\n",
+            yfile->index,
+            vma->vm_pgoff,
+            (vma->vm_end - vma->vm_start));
+
+    mutex_lock(&yfile->device->mutex);
+
+    if (vma->vm_pgoff == 0) {
+        /*
+         * First page is 'regs'.
+         */
 
-        buff = NULL;
+        ret = yagl_misc_mmap_regs(yfile, vma);
+    } else if (vma->vm_pgoff == 1) {
+        /*
+         * Everything else is buffer.
+         */
 
-        dprintk("%s: YaGL entered\n",
-                yfile->device->miscdev.name);
+        ret = yagl_misc_mmap_buffer(yfile, vma);
     } else {
-        dprintk("%s: mmap must be called with page offset 0 or 1\n",
-                yfile->device->miscdev.name);
+        dprintk("%d mmap must be called with page offset 0 or 1\n",
+                yfile->index);
         ret = -EINVAL;
+    }
+
+    mutex_unlock(&yfile->device->mutex);
+
+    return ret;
+}
+
+static int yagl_misc_mlock(struct yagl_file *yfile,
+                           const struct yagl_mlock_arg *arg)
+{
+    int ret, i;
+    unsigned long address = arg->address & PAGE_MASK;
+    struct yagl_mlock *mlock;
+
+    dprintk("user = %d, address = %p, size = %u\n",
+            yfile->index,
+            (void*)arg->address,
+            arg->size);
+
+    if (arg->size == 0) {
+        dprintk("%d unable to mlock 0 bytes\n",
+                yfile->index);
+        return -EFAULT;
+    }
+
+    down_read(&current->mm->mmap_sem);
+    mutex_lock(&yfile->device->mutex);
+
+    list_for_each_entry(mlock, &yfile->mlock_list, list) {
+        if (mlock->address == address) {
+            dprintk("%d address %p already locked\n",
+                    yfile->index,
+                    (void*)address);
+            ret = -EEXIST;
+            goto out;
+        }
+    }
+
+    mlock = kzalloc(sizeof(*mlock), GFP_KERNEL);
+
+    if (!mlock) {
+        dprintk("%d unable to allocate memory\n",
+                yfile->index);
+        ret = -ENOMEM;
+        goto out;
+    }
+
+    mlock->address = address;
+    mlock->num_pages = PAGE_ALIGN((arg->address & ~PAGE_MASK) + arg->size) >> PAGE_SHIFT;
+    mlock->pages = kzalloc(mlock->num_pages * sizeof(*mlock->pages), GFP_KERNEL);
+
+    if (!mlock->pages) {
+        dprintk("%d unable to allocate memory\n",
+                yfile->index);
+        kfree(mlock);
+        ret = -ENOMEM;
         goto out;
     }
 
+    ret = get_user_pages(current, current->mm, mlock->address,
+                         mlock->num_pages, 1, 0, mlock->pages, NULL);
+
+    if (ret < (int)mlock->num_pages) {
+        mutex_unlock(&yfile->device->mutex);
+        up_read(&current->mm->mmap_sem);
+
+        for (i = 0; i < ret; ++i) {
+            put_page(mlock->pages[i]);
+        }
+        kfree(mlock->pages);
+        kfree(mlock);
+
+        ret = (ret >= 0) ? -EFAULT : ret;
+
+        dprintk("%d unable to get user pages: %d\n",
+                yfile->index,
+                ret);
+
+        return ret;
+    }
+
+    INIT_LIST_HEAD(&mlock->list);
+
+    list_add_tail(&mlock->list, &yfile->mlock_list);
+
     ret = 0;
 
 out:
-    if (buff) {
-        free_pages((unsigned long)buff, get_order(vma->vm_end - vma->vm_start));
-    }
     mutex_unlock(&yfile->device->mutex);
+    up_read(&current->mm->mmap_sem);
 
     return ret;
 }
 
+static int yagl_misc_munlock(struct yagl_file *yfile,
+                             unsigned long address)
+{
+    u32 i;
+    struct yagl_mlock *mlock;
+
+    dprintk("user = %d, address = %p\n",
+            yfile->index,
+            (void*)address);
+
+    address &= PAGE_MASK;
+
+    mutex_lock(&yfile->device->mutex);
+
+    list_for_each_entry(mlock, &yfile->mlock_list, list) {
+        if (mlock->address == address) {
+            for (i = 0; i < mlock->num_pages; ++i) {
+                set_page_dirty_lock(mlock->pages[i]);
+                put_page(mlock->pages[i]);
+            }
+            kfree(mlock->pages);
+            list_del(&mlock->list);
+            kfree(mlock);
+
+            mutex_unlock(&yfile->device->mutex);
+
+            return 0;
+        }
+    }
+
+    mutex_unlock(&yfile->device->mutex);
+
+    dprintk("%d address %p not locked\n",
+            yfile->index,
+            (void*)address);
+
+    return -ENOENT;
+}
+
 static long yagl_misc_ioctl(struct file* file, unsigned int cmd, unsigned long arg)
 {
+    struct yagl_file *yfile = file->private_data;
     int ret = 0;
-    unsigned int value = 0;
+    union
+    {
+        unsigned int uint;
+        unsigned long ulong;
+        struct yagl_user_info user_info;
+        struct yagl_mlock_arg mlock_arg;
+    } value;
 
     if (_IOC_TYPE(cmd) != YAGL_IOC_MAGIC) {
         return -ENOTTY;
@@ -335,8 +659,32 @@ static long yagl_misc_ioctl(struct file* file, unsigned int cmd, unsigned long a
 
     switch (cmd) {
     case YAGL_IOC_GET_VERSION:
-        value = YAGL_VERSION;
-        ret = put_user(value, (unsigned int __user*)arg);
+        value.uint = YAGL_VERSION;
+        ret = put_user(value.uint, (unsigned int __user*)arg);
+        break;
+    case YAGL_IOC_GET_USER_INFO:
+        value.user_info.index = yfile->index;
+        value.user_info.render_type = yfile->render_type;
+        if (copy_to_user((struct yagl_user_info __user*)arg,
+                         &value.user_info,
+                         sizeof(value.user_info)) != 0) {
+            ret = -EFAULT;
+        }
+        break;
+    case YAGL_IOC_MLOCK:
+        if (copy_from_user(&value.mlock_arg,
+                           (struct yagl_mlock_arg __user*)arg,
+                           sizeof(value.mlock_arg)) == 0) {
+            ret = yagl_misc_mlock(yfile, &value.mlock_arg);
+        } else {
+            ret = -EFAULT;
+        }
+        break;
+    case YAGL_IOC_MUNLOCK:
+        ret = get_user(value.ulong, (unsigned long __user*)arg);
+        if (ret == 0) {
+            ret = yagl_misc_munlock(yfile, value.ulong);
+        }
         break;
     default:
         ret = -ENOTTY;
diff --git a/drivers/gpu/yagl/yagl_ioctl.h b/drivers/gpu/yagl/yagl_ioctl.h
new file mode 100644 (file)
index 0000000..aa7374d
--- /dev/null
@@ -0,0 +1,52 @@
+#ifndef _YAGL_IOCTL_H_
+#define _YAGL_IOCTL_H_
+
+#include <linux/ioctl.h>
+
+/*
+ * Version number.
+ */
+#define YAGL_VERSION 20
+
+/*
+ * Device control codes magic.
+ */
+#define YAGL_IOC_MAGIC 'Y'
+
+/*
+ * Get version number.
+ */
+#define YAGL_IOC_GET_VERSION _IOR(YAGL_IOC_MAGIC, 0, unsigned int)
+
+/*
+ * Get user info.
+ */
+struct yagl_user_info
+{
+    unsigned int index;
+    unsigned int render_type;
+};
+
+#define YAGL_IOC_GET_USER_INFO _IOR(YAGL_IOC_MAGIC, 1, struct yagl_user_info)
+
+/*
+ * Locks/unlocks memory. Exists solely
+ * for offscreen backend's backing images.
+ * @{
+ */
+
+struct yagl_mlock_arg
+{
+    unsigned long address;
+    unsigned int size;
+};
+
+#define YAGL_IOC_MLOCK _IOW(YAGL_IOC_MAGIC, 2, struct yagl_mlock_arg)
+
+#define YAGL_IOC_MUNLOCK _IOW(YAGL_IOC_MAGIC, 3, unsigned long)
+
+/*
+ * @}
+ */
+
+#endif
diff --git a/drivers/gpu/yagl/yagl_marshal.h b/drivers/gpu/yagl/yagl_marshal.h
deleted file mode 100644 (file)
index 368a2bd..0000000
+++ /dev/null
@@ -1,32 +0,0 @@
-#ifndef _YAGL_MARSHAL_H_
-#define _YAGL_MARSHAL_H_
-
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <asm/byteorder.h>
-
-/*
- * All marshalling/unmarshalling must be done with 8-byte alignment,
- * since this is the maximum alignment possible. This way we can
- * just do assignments without "memcpy" calls and can be sure that
- * the code won't fail on architectures that don't support unaligned
- * memory access.
- */
-
-static __inline void yagl_marshal_put_uint32(u8** buff, u32 value)
-{
-    *(u32*)(*buff) = cpu_to_le32(value);
-    *buff += 8;
-}
-
-static __inline u32 yagl_marshal_get_uint32(u8** buff)
-{
-    u32 tmp = le32_to_cpu(*(u32*)*buff);
-    *buff += 8;
-    return tmp;
-}
-
-#define yagl_marshal_put_pid(buff, value) yagl_marshal_put_uint32(buff, value)
-#define yagl_marshal_put_tid(buff, value) yagl_marshal_put_uint32(buff, value)
-
-#endif
diff --git a/drivers/gpu/yagl/yagl_version.h b/drivers/gpu/yagl/yagl_version.h
deleted file mode 100644 (file)
index 7c214b2..0000000
+++ /dev/null
@@ -1,21 +0,0 @@
-#ifndef _YAGL_VERSION_H_
-#define _YAGL_VERSION_H_
-
-#include <linux/ioctl.h>
-
-/*
- * Version number.
- */
-#define YAGL_VERSION 19
-
-/*
- * Device control codes magic.
- */
-#define YAGL_IOC_MAGIC 'Y'
-
-/*
- * Get version number.
- */
-#define YAGL_IOC_GET_VERSION _IOR(YAGL_IOC_MAGIC, 0, unsigned int)
-
-#endif