ANDROID: goldfish_sync: Isolate single module to fix compilation
authorDmitry Shmidt <dimitrysh@google.com>
Tue, 7 Feb 2017 19:09:30 +0000 (11:09 -0800)
committerAmit Pundir <amit.pundir@linaro.org>
Mon, 18 Dec 2017 15:41:22 +0000 (21:11 +0530)
ERROR: "goldfish_sync_timeline_signal_internal"
   [drivers/staging/goldfish/goldfish_sync.ko] undefined!
ERROR: "goldfish_sync_timeline_create_internal"
   [drivers/staging/goldfish/goldfish_sync.ko] undefined!
ERROR: "goldfish_sync_pt_create_internal"
   [drivers/staging/goldfish/goldfish_sync.ko] undefined!
ERROR: "goldfish_sync_timeline_put_internal"
   [drivers/staging/goldfish/goldfish_sync.ko] undefined!

Change-Id: I2a97c2a33b38ceeb696d28187539c158aa97a620
Signed-off-by: Dmitry Shmidt <dimitrysh@google.com>
drivers/staging/goldfish/Makefile
drivers/staging/goldfish/goldfish_sync.c [deleted file]
drivers/staging/goldfish/goldfish_sync_timeline.c [new file with mode: 0644]

index fbebfb7c781cb592c1eaafaa3ad7ad17970bfc6f..3313fce4e940d7be564416ca1485225ab41aba4b 100644 (file)
@@ -8,5 +8,5 @@ obj-$(CONFIG_MTD_GOLDFISH_NAND) += goldfish_nand.o
 # and sync
 
 ccflags-y := -Idrivers/staging/android
-obj-$(CONFIG_GOLDFISH_SYNC) += goldfish_sync_timeline_fence.o
+goldfish_sync-objs := goldfish_sync_timeline_fence.o goldfish_sync_timeline.o
 obj-$(CONFIG_GOLDFISH_SYNC) += goldfish_sync.o
diff --git a/drivers/staging/goldfish/goldfish_sync.c b/drivers/staging/goldfish/goldfish_sync.c
deleted file mode 100644 (file)
index aeccec1..0000000
+++ /dev/null
@@ -1,963 +0,0 @@
-/*
- * Copyright (C) 2016 Google, Inc.
- *
- * This software is licensed under the terms of the GNU General Public
- * License version 2, as published by the Free Software Foundation, and
- * may be copied, distributed, and modified under those terms.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- */
-
-#include <linux/fdtable.h>
-#include <linux/file.h>
-#include <linux/init.h>
-#include <linux/miscdevice.h>
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/platform_device.h>
-
-#include <linux/interrupt.h>
-#include <linux/kref.h>
-#include <linux/spinlock.h>
-#include <linux/types.h>
-
-#include <linux/io.h>
-#include <linux/mm.h>
-#include <linux/acpi.h>
-
-#include <linux/string.h>
-
-#include <linux/fs.h>
-#include <linux/syscalls.h>
-#include <linux/sync_file.h>
-#include <linux/fence.h>
-
-#include "goldfish_sync_timeline_fence.h"
-
-#define ERR(...) printk(KERN_ERR __VA_ARGS__);
-
-#define INFO(...) printk(KERN_INFO __VA_ARGS__);
-
-#define DPRINT(...) pr_debug(__VA_ARGS__);
-
-#define DTRACE() DPRINT("%s: enter", __func__)
-
-/* The Goldfish sync driver is designed to provide a interface
- * between the underlying host's sync device and the kernel's
- * fence sync framework..
- * The purpose of the device/driver is to enable lightweight
- * creation and signaling of timelines and fences
- * in order to synchronize the guest with host-side graphics events.
- *
- * Each time the interrupt trips, the driver
- * may perform a sync operation.
- */
-
-/* The operations are: */
-
-/* Ready signal - used to mark when irq should lower */
-#define CMD_SYNC_READY            0
-
-/* Create a new timeline. writes timeline handle */
-#define CMD_CREATE_SYNC_TIMELINE  1
-
-/* Create a fence object. reads timeline handle and time argument.
- * Writes fence fd to the SYNC_REG_HANDLE register. */
-#define CMD_CREATE_SYNC_FENCE     2
-
-/* Increments timeline. reads timeline handle and time argument */
-#define CMD_SYNC_TIMELINE_INC     3
-
-/* Destroys a timeline. reads timeline handle */
-#define CMD_DESTROY_SYNC_TIMELINE 4
-
-/* Starts a wait on the host with
- * the given glsync object and sync thread handle. */
-#define CMD_TRIGGER_HOST_WAIT     5
-
-/* The register layout is: */
-
-#define SYNC_REG_BATCH_COMMAND                0x00 /* host->guest batch commands */
-#define SYNC_REG_BATCH_GUESTCOMMAND           0x04 /* guest->host batch commands */
-#define SYNC_REG_BATCH_COMMAND_ADDR           0x08 /* communicate physical address of host->guest batch commands */
-#define SYNC_REG_BATCH_COMMAND_ADDR_HIGH      0x0c /* 64-bit part */
-#define SYNC_REG_BATCH_GUESTCOMMAND_ADDR      0x10 /* communicate physical address of guest->host commands */
-#define SYNC_REG_BATCH_GUESTCOMMAND_ADDR_HIGH 0x14 /* 64-bit part */
-#define SYNC_REG_INIT                         0x18 /* signals that the device has been probed */
-
-/* There is an ioctl associated with goldfish sync driver.
- * Make it conflict with ioctls that are not likely to be used
- * in the emulator.
- *
- * '@' 00-0F   linux/radeonfb.h        conflict!
- * '@' 00-0F   drivers/video/aty/aty128fb.c    conflict!
- */
-#define GOLDFISH_SYNC_IOC_MAGIC        '@'
-
-#define GOLDFISH_SYNC_IOC_QUEUE_WORK   _IOWR(GOLDFISH_SYNC_IOC_MAGIC, 0, struct goldfish_sync_ioctl_info)
-
-/* The above definitions (command codes, register layout, ioctl definitions)
- * need to be in sync with the following files:
- *
- * Host-side (emulator):
- * external/qemu/android/emulation/goldfish_sync.h
- * external/qemu-android/hw/misc/goldfish_sync.c
- *
- * Guest-side (system image):
- * device/generic/goldfish-opengl/system/egl/goldfish_sync.h
- * device/generic/goldfish/ueventd.ranchu.rc
- * platform/build/target/board/generic/sepolicy/file_contexts
- */
-struct goldfish_sync_hostcmd {
-       /* sorted for alignment */
-       uint64_t handle;
-       uint64_t hostcmd_handle;
-       uint32_t cmd;
-       uint32_t time_arg;
-};
-
-struct goldfish_sync_guestcmd {
-       uint64_t host_command; /* uint64_t for alignment */
-       uint64_t glsync_handle;
-       uint64_t thread_handle;
-       uint64_t guest_timeline_handle;
-};
-
-#define GOLDFISH_SYNC_MAX_CMDS 64
-
-struct goldfish_sync_state {
-       char __iomem *reg_base;
-       int irq;
-
-       /* Spinlock protects |to_do| / |to_do_end|. */
-       spinlock_t lock;
-       /* |mutex_lock| protects all concurrent access
-        * to timelines for both kernel and user space. */
-       struct mutex mutex_lock;
-
-       /* Buffer holding commands issued from host. */
-       struct goldfish_sync_hostcmd to_do[GOLDFISH_SYNC_MAX_CMDS];
-       uint32_t to_do_end;
-
-       /* Addresses for the reading or writing
-        * of individual commands. The host can directly write
-        * to |batch_hostcmd| (and then this driver immediately
-        * copies contents to |to_do|). This driver either replies
-        * through |batch_hostcmd| or simply issues a
-        * guest->host command through |batch_guestcmd|.
-        */
-       struct goldfish_sync_hostcmd *batch_hostcmd;
-       struct goldfish_sync_guestcmd *batch_guestcmd;
-
-       /* Used to give this struct itself to a work queue
-        * function for executing actual sync commands. */
-       struct work_struct work_item;
-};
-
-static struct goldfish_sync_state global_sync_state[1];
-
-struct goldfish_sync_timeline_obj {
-       struct goldfish_sync_timeline *sync_tl;
-       uint32_t current_time;
-       /* We need to be careful about when we deallocate
-        * this |goldfish_sync_timeline_obj| struct.
-        * In order to ensure proper cleanup, we need to
-        * consider the triggered host-side wait that may
-        * still be in flight when the guest close()'s a
-        * goldfish_sync device's sync context fd (and
-        * destroys the |sync_tl| field above).
-        * The host-side wait may raise IRQ
-        * and tell the kernel to increment the timeline _after_
-        * the |sync_tl| has already been set to null.
-        *
-        * From observations on OpenGL apps and CTS tests, this
-        * happens at some very low probability upon context
-        * destruction or process close, but it does happen
-        * and it needs to be handled properly. Otherwise,
-        * if we clean up the surrounding |goldfish_sync_timeline_obj|
-        * too early, any |handle| field of any host->guest command
-        * might not even point to a null |sync_tl| field,
-        * but to garbage memory or even a reclaimed |sync_tl|.
-        * If we do not count such "pending waits" and kfree the object
-        * immediately upon |goldfish_sync_timeline_destroy|,
-        * we might get mysterous RCU stalls after running a long
-        * time because the garbage memory that is being read
-        * happens to be interpretable as a |spinlock_t| struct
-        * that is currently in the locked state.
-        *
-        * To track when to free the |goldfish_sync_timeline_obj|
-        * itself, we maintain a kref.
-        * The kref essentially counts the timeline itself plus
-        * the number of waits in flight. kref_init/kref_put
-        * are issued on
-        * |goldfish_sync_timeline_create|/|goldfish_sync_timeline_destroy|
-        * and kref_get/kref_put are issued on
-        * |goldfish_sync_fence_create|/|goldfish_sync_timeline_inc|.
-        *
-        * The timeline is destroyed after reference count
-        * reaches zero, which would happen after
-        * |goldfish_sync_timeline_destroy| and all pending
-        * |goldfish_sync_timeline_inc|'s are fulfilled.
-        *
-        * NOTE (1): We assume that |fence_create| and
-        * |timeline_inc| calls are 1:1, otherwise the kref scheme
-        * will not work. This is a valid assumption as long
-        * as the host-side virtual device implementation
-        * does not insert any timeline increments
-        * that we did not trigger from here.
-        *
-        * NOTE (2): The use of kref by itself requires no locks,
-        * but this does not mean everything works without locks.
-        * Related timeline operations do require a lock of some sort,
-        * or at least are not proven to work without it.
-        * In particualr, we assume that all the operations
-        * done on the |kref| field above are done in contexts where
-        * |global_sync_state->mutex_lock| is held. Do not
-        * remove that lock until everything is proven to work
-        * without it!!! */
-       struct kref kref;
-};
-
-/* We will call |delete_timeline_obj| when the last reference count
- * of the kref is decremented. This deletes the sync
- * timeline object along with the wrapper itself. */
-static void delete_timeline_obj(struct kref* kref) {
-       struct goldfish_sync_timeline_obj* obj =
-               container_of(kref, struct goldfish_sync_timeline_obj, kref);
-
-       goldfish_sync_timeline_put_internal(obj->sync_tl);
-       obj->sync_tl = NULL;
-       kfree(obj);
-}
-
-static uint64_t gensym_ctr;
-static void gensym(char *dst)
-{
-       sprintf(dst, "goldfish_sync:gensym:%llu", gensym_ctr);
-       gensym_ctr++;
-}
-
-/* |goldfish_sync_timeline_create| assumes that |global_sync_state->mutex_lock|
- * is held. */
-static struct goldfish_sync_timeline_obj*
-goldfish_sync_timeline_create(void)
-{
-
-       char timeline_name[256];
-       struct goldfish_sync_timeline *res_sync_tl = NULL;
-       struct goldfish_sync_timeline_obj *res;
-
-       DTRACE();
-
-       gensym(timeline_name);
-
-       res_sync_tl = goldfish_sync_timeline_create_internal(timeline_name);
-       if (!res_sync_tl) {
-               ERR("Failed to create goldfish_sw_sync timeline.");
-               return NULL;
-       }
-
-       res = kzalloc(sizeof(struct goldfish_sync_timeline_obj), GFP_KERNEL);
-       res->sync_tl = res_sync_tl;
-       res->current_time = 0;
-       kref_init(&res->kref);
-
-       DPRINT("new timeline_obj=0x%p", res);
-       return res;
-}
-
-/* |goldfish_sync_fence_create| assumes that |global_sync_state->mutex_lock|
- * is held. */
-static int
-goldfish_sync_fence_create(struct goldfish_sync_timeline_obj *obj,
-                                                       uint32_t val)
-{
-
-       int fd;
-       char fence_name[256];
-       struct sync_pt *syncpt = NULL;
-       struct sync_file *sync_file_obj = NULL;
-       struct goldfish_sync_timeline *tl;
-
-       DTRACE();
-
-       if (!obj) return -1;
-
-       tl = obj->sync_tl;
-
-       syncpt = goldfish_sync_pt_create_internal(
-                               tl, sizeof(struct sync_pt) + 4, val);
-       if (!syncpt) {
-               ERR("could not create sync point! "
-                       "goldfish_sync_timeline=0x%p val=%d",
-                          tl, val);
-               return -1;
-       }
-
-       fd = get_unused_fd_flags(O_CLOEXEC);
-       if (fd < 0) {
-               ERR("could not get unused fd for sync fence. "
-                       "errno=%d", fd);
-               goto err_cleanup_pt;
-       }
-
-       gensym(fence_name);
-
-       sync_file_obj = sync_file_create(&syncpt->base);
-       if (!sync_file_obj) {
-               ERR("could not create sync fence! "
-                       "goldfish_sync_timeline=0x%p val=%d sync_pt=0x%p",
-                          tl, val, syncpt);
-               goto err_cleanup_fd_pt;
-       }
-
-       DPRINT("installing sync fence into fd %d sync_file_obj=0x%p",
-                       fd, sync_file_obj);
-       fd_install(fd, sync_file_obj->file);
-       kref_get(&obj->kref);
-
-       return fd;
-
-err_cleanup_fd_pt:
-       fput(sync_file_obj->file);
-       put_unused_fd(fd);
-err_cleanup_pt:
-       fence_put(&syncpt->base);
-       return -1;
-}
-
-/* |goldfish_sync_timeline_inc| assumes that |global_sync_state->mutex_lock|
- * is held. */
-static void
-goldfish_sync_timeline_inc(struct goldfish_sync_timeline_obj *obj, uint32_t inc)
-{
-       DTRACE();
-       /* Just give up if someone else nuked the timeline.
-        * Whoever it was won't care that it doesn't get signaled. */
-       if (!obj) return;
-
-       DPRINT("timeline_obj=0x%p", obj);
-       goldfish_sync_timeline_signal_internal(obj->sync_tl, inc);
-       DPRINT("incremented timeline. increment max_time");
-       obj->current_time += inc;
-
-       /* Here, we will end up deleting the timeline object if it
-        * turns out that this call was a pending increment after
-        * |goldfish_sync_timeline_destroy| was called. */
-       kref_put(&obj->kref, delete_timeline_obj);
-       DPRINT("done");
-}
-
-/* |goldfish_sync_timeline_destroy| assumes
- * that |global_sync_state->mutex_lock| is held. */
-static void
-goldfish_sync_timeline_destroy(struct goldfish_sync_timeline_obj *obj)
-{
-       DTRACE();
-       /* See description of |goldfish_sync_timeline_obj| for why we
-        * should not immediately destroy |obj| */
-       kref_put(&obj->kref, delete_timeline_obj);
-}
-
-static inline void
-goldfish_sync_cmd_queue(struct goldfish_sync_state *sync_state,
-                                               uint32_t cmd,
-                                               uint64_t handle,
-                                               uint32_t time_arg,
-                                               uint64_t hostcmd_handle)
-{
-       struct goldfish_sync_hostcmd *to_add;
-
-       DTRACE();
-
-       BUG_ON(sync_state->to_do_end == GOLDFISH_SYNC_MAX_CMDS);
-
-       to_add = &sync_state->to_do[sync_state->to_do_end];
-
-       to_add->cmd = cmd;
-       to_add->handle = handle;
-       to_add->time_arg = time_arg;
-       to_add->hostcmd_handle = hostcmd_handle;
-
-       sync_state->to_do_end += 1;
-}
-
-static inline void
-goldfish_sync_hostcmd_reply(struct goldfish_sync_state *sync_state,
-                                                       uint32_t cmd,
-                                                       uint64_t handle,
-                                                       uint32_t time_arg,
-                                                       uint64_t hostcmd_handle)
-{
-       unsigned long irq_flags;
-       struct goldfish_sync_hostcmd *batch_hostcmd =
-               sync_state->batch_hostcmd;
-
-       DTRACE();
-
-       spin_lock_irqsave(&sync_state->lock, irq_flags);
-
-       batch_hostcmd->cmd = cmd;
-       batch_hostcmd->handle = handle;
-       batch_hostcmd->time_arg = time_arg;
-       batch_hostcmd->hostcmd_handle = hostcmd_handle;
-       writel(0, sync_state->reg_base + SYNC_REG_BATCH_COMMAND);
-
-       spin_unlock_irqrestore(&sync_state->lock, irq_flags);
-}
-
-static inline void
-goldfish_sync_send_guestcmd(struct goldfish_sync_state *sync_state,
-                                                       uint32_t cmd,
-                                                       uint64_t glsync_handle,
-                                                       uint64_t thread_handle,
-                                                       uint64_t timeline_handle)
-{
-       unsigned long irq_flags;
-       struct goldfish_sync_guestcmd *batch_guestcmd =
-               sync_state->batch_guestcmd;
-
-       DTRACE();
-
-       spin_lock_irqsave(&sync_state->lock, irq_flags);
-
-       batch_guestcmd->host_command = (uint64_t)cmd;
-       batch_guestcmd->glsync_handle = (uint64_t)glsync_handle;
-       batch_guestcmd->thread_handle = (uint64_t)thread_handle;
-       batch_guestcmd->guest_timeline_handle = (uint64_t)timeline_handle;
-       writel(0, sync_state->reg_base + SYNC_REG_BATCH_GUESTCOMMAND);
-
-       spin_unlock_irqrestore(&sync_state->lock, irq_flags);
-}
-
-/* |goldfish_sync_interrupt| handles IRQ raises from the virtual device.
- * In the context of OpenGL, this interrupt will fire whenever we need
- * to signal a fence fd in the guest, with the command
- * |CMD_SYNC_TIMELINE_INC|.
- * However, because this function will be called in an interrupt context,
- * it is necessary to do the actual work of signaling off of interrupt context.
- * The shared work queue is used for this purpose. At the end when
- * all pending commands are intercepted by the interrupt handler,
- * we call |schedule_work|, which will later run the actual
- * desired sync command in |goldfish_sync_work_item_fn|.
- */
-static irqreturn_t goldfish_sync_interrupt(int irq, void *dev_id)
-{
-
-       struct goldfish_sync_state *sync_state = dev_id;
-
-       uint32_t nextcmd;
-       uint32_t command_r;
-       uint64_t handle_rw;
-       uint32_t time_r;
-       uint64_t hostcmd_handle_rw;
-
-       int count = 0;
-
-       DTRACE();
-
-       sync_state = dev_id;
-
-       spin_lock(&sync_state->lock);
-
-       for (;;) {
-
-               readl(sync_state->reg_base + SYNC_REG_BATCH_COMMAND);
-               nextcmd = sync_state->batch_hostcmd->cmd;
-
-               if (nextcmd == 0)
-                       break;
-
-               command_r = nextcmd;
-               handle_rw = sync_state->batch_hostcmd->handle;
-               time_r = sync_state->batch_hostcmd->time_arg;
-               hostcmd_handle_rw = sync_state->batch_hostcmd->hostcmd_handle;
-
-               goldfish_sync_cmd_queue(
-                               sync_state,
-                               command_r,
-                               handle_rw,
-                               time_r,
-                               hostcmd_handle_rw);
-
-               count++;
-       }
-
-       spin_unlock(&sync_state->lock);
-
-       schedule_work(&sync_state->work_item);
-
-       return (count == 0) ? IRQ_NONE : IRQ_HANDLED;
-}
-
-/* |goldfish_sync_work_item_fn| does the actual work of servicing
- * host->guest sync commands. This function is triggered whenever
- * the IRQ for the goldfish sync device is raised. Once it starts
- * running, it grabs the contents of the buffer containing the
- * commands it needs to execute (there may be multiple, because
- * our IRQ is active high and not edge triggered), and then
- * runs all of them one after the other.
- */
-static void goldfish_sync_work_item_fn(struct work_struct *input)
-{
-
-       struct goldfish_sync_state *sync_state;
-       int sync_fence_fd;
-
-       struct goldfish_sync_timeline_obj *timeline;
-       uint64_t timeline_ptr;
-
-       uint64_t hostcmd_handle;
-
-       uint32_t cmd;
-       uint64_t handle;
-       uint32_t time_arg;
-
-       struct goldfish_sync_hostcmd *todo;
-       uint32_t todo_end;
-
-       unsigned long irq_flags;
-
-       struct goldfish_sync_hostcmd to_run[GOLDFISH_SYNC_MAX_CMDS];
-       uint32_t i = 0;
-
-       sync_state = container_of(input, struct goldfish_sync_state, work_item);
-
-       mutex_lock(&sync_state->mutex_lock);
-
-       spin_lock_irqsave(&sync_state->lock, irq_flags); {
-
-               todo_end = sync_state->to_do_end;
-
-               DPRINT("num sync todos: %u", sync_state->to_do_end);
-
-               for (i = 0; i < todo_end; i++)
-                       to_run[i] = sync_state->to_do[i];
-
-               /* We expect that commands will come in at a slow enough rate
-                * so that incoming items will not be more than
-                * GOLDFISH_SYNC_MAX_CMDS.
-                *
-                * This is because the way the sync device is used,
-                * it's only for managing buffer data transfers per frame,
-                * with a sequential dependency between putting things in
-                * to_do and taking them out. Once a set of commands is
-                * queued up in to_do, the user of the device waits for
-                * them to be processed before queuing additional commands,
-                * which limits the rate at which commands come in
-                * to the rate at which we take them out here.
-                *
-                * We also don't expect more than MAX_CMDS to be issued
-                * at once; there is a correspondence between
-                * which buffers need swapping to the (display / buffer queue)
-                * to particular commands, and we don't expect there to be
-                * enough display or buffer queues in operation at once
-                * to overrun GOLDFISH_SYNC_MAX_CMDS.
-                */
-               sync_state->to_do_end = 0;
-
-       } spin_unlock_irqrestore(&sync_state->lock, irq_flags);
-
-       for (i = 0; i < todo_end; i++) {
-               DPRINT("todo index: %u", i);
-
-               todo = &to_run[i];
-
-               cmd = todo->cmd;
-
-               handle = (uint64_t)todo->handle;
-               time_arg = todo->time_arg;
-               hostcmd_handle = (uint64_t)todo->hostcmd_handle;
-
-               DTRACE();
-
-               timeline = (struct goldfish_sync_timeline_obj *)(uintptr_t)handle;
-
-               switch (cmd) {
-               case CMD_SYNC_READY:
-                       break;
-               case CMD_CREATE_SYNC_TIMELINE:
-                       DPRINT("exec CMD_CREATE_SYNC_TIMELINE: "
-                                       "handle=0x%llx time_arg=%d",
-                                       handle, time_arg);
-                       timeline = goldfish_sync_timeline_create();
-                       timeline_ptr = (uintptr_t)timeline;
-                       goldfish_sync_hostcmd_reply(sync_state, CMD_CREATE_SYNC_TIMELINE,
-                                                                               timeline_ptr,
-                                                                               0,
-                                                                               hostcmd_handle);
-                       DPRINT("sync timeline created: %p", timeline);
-                       break;
-               case CMD_CREATE_SYNC_FENCE:
-                       DPRINT("exec CMD_CREATE_SYNC_FENCE: "
-                                       "handle=0x%llx time_arg=%d",
-                                       handle, time_arg);
-                       sync_fence_fd = goldfish_sync_fence_create(timeline, time_arg);
-                       goldfish_sync_hostcmd_reply(sync_state, CMD_CREATE_SYNC_FENCE,
-                                                                               sync_fence_fd,
-                                                                               0,
-                                                                               hostcmd_handle);
-                       break;
-               case CMD_SYNC_TIMELINE_INC:
-                       DPRINT("exec CMD_SYNC_TIMELINE_INC: "
-                                       "handle=0x%llx time_arg=%d",
-                                       handle, time_arg);
-                       goldfish_sync_timeline_inc(timeline, time_arg);
-                       break;
-               case CMD_DESTROY_SYNC_TIMELINE:
-                       DPRINT("exec CMD_DESTROY_SYNC_TIMELINE: "
-                                       "handle=0x%llx time_arg=%d",
-                                       handle, time_arg);
-                       goldfish_sync_timeline_destroy(timeline);
-                       break;
-               }
-               DPRINT("Done executing sync command");
-       }
-       mutex_unlock(&sync_state->mutex_lock);
-}
-
-/* Guest-side interface: file operations */
-
-/* Goldfish sync context and ioctl info.
- *
- * When a sync context is created by open()-ing the goldfish sync device, we
- * create a sync context (|goldfish_sync_context|).
- *
- * Currently, the only data required to track is the sync timeline itself
- * along with the current time, which are all packed up in the
- * |goldfish_sync_timeline_obj| field. We use a |goldfish_sync_context|
- * as the filp->private_data.
- *
- * Next, when a sync context user requests that work be queued and a fence
- * fd provided, we use the |goldfish_sync_ioctl_info| struct, which holds
- * information about which host handles to touch for this particular
- * queue-work operation. We need to know about the host-side sync thread
- * and the particular host-side GLsync object. We also possibly write out
- * a file descriptor.
- */
-struct goldfish_sync_context {
-       struct goldfish_sync_timeline_obj *timeline;
-};
-
-struct goldfish_sync_ioctl_info {
-       uint64_t host_glsync_handle_in;
-       uint64_t host_syncthread_handle_in;
-       int fence_fd_out;
-};
-
-static int goldfish_sync_open(struct inode *inode, struct file *file)
-{
-
-       struct goldfish_sync_context *sync_context;
-
-       DTRACE();
-
-       mutex_lock(&global_sync_state->mutex_lock);
-
-       sync_context = kzalloc(sizeof(struct goldfish_sync_context), GFP_KERNEL);
-
-       if (sync_context == NULL) {
-               ERR("Creation of goldfish sync context failed!");
-               mutex_unlock(&global_sync_state->mutex_lock);
-               return -ENOMEM;
-       }
-
-       sync_context->timeline = NULL;
-
-       file->private_data = sync_context;
-
-       DPRINT("successfully create a sync context @0x%p", sync_context);
-
-       mutex_unlock(&global_sync_state->mutex_lock);
-
-       return 0;
-}
-
-static int goldfish_sync_release(struct inode *inode, struct file *file)
-{
-
-       struct goldfish_sync_context *sync_context;
-
-       DTRACE();
-
-       mutex_lock(&global_sync_state->mutex_lock);
-
-       sync_context = file->private_data;
-
-       if (sync_context->timeline)
-               goldfish_sync_timeline_destroy(sync_context->timeline);
-
-       sync_context->timeline = NULL;
-
-       kfree(sync_context);
-
-       mutex_unlock(&global_sync_state->mutex_lock);
-
-       return 0;
-}
-
-/* |goldfish_sync_ioctl| is the guest-facing interface of goldfish sync
- * and is used in conjunction with eglCreateSyncKHR to queue up the
- * actual work of waiting for the EGL sync command to complete,
- * possibly returning a fence fd to the guest.
- */
-static long goldfish_sync_ioctl(struct file *file,
-                                                               unsigned int cmd,
-                                                               unsigned long arg)
-{
-       struct goldfish_sync_context *sync_context_data;
-       struct goldfish_sync_timeline_obj *timeline;
-       int fd_out;
-       struct goldfish_sync_ioctl_info ioctl_data;
-
-       DTRACE();
-
-       sync_context_data = file->private_data;
-       fd_out = -1;
-
-       switch (cmd) {
-       case GOLDFISH_SYNC_IOC_QUEUE_WORK:
-
-               DPRINT("exec GOLDFISH_SYNC_IOC_QUEUE_WORK");
-
-               mutex_lock(&global_sync_state->mutex_lock);
-
-               if (copy_from_user(&ioctl_data,
-                                               (void __user *)arg,
-                                               sizeof(ioctl_data))) {
-                       ERR("Failed to copy memory for ioctl_data from user.");
-                       mutex_unlock(&global_sync_state->mutex_lock);
-                       return -EFAULT;
-               }
-
-               if (ioctl_data.host_syncthread_handle_in == 0) {
-                       DPRINT("Error: zero host syncthread handle!!!");
-                       mutex_unlock(&global_sync_state->mutex_lock);
-                       return -EFAULT;
-               }
-
-               if (!sync_context_data->timeline) {
-                       DPRINT("no timeline yet, create one.");
-                       sync_context_data->timeline = goldfish_sync_timeline_create();
-                       DPRINT("timeline: 0x%p", &sync_context_data->timeline);
-               }
-
-               timeline = sync_context_data->timeline;
-               fd_out = goldfish_sync_fence_create(timeline,
-                                                                                       timeline->current_time + 1);
-               DPRINT("Created fence with fd %d and current time %u (timeline: 0x%p)",
-                          fd_out,
-                          sync_context_data->timeline->current_time + 1,
-                          sync_context_data->timeline);
-
-               ioctl_data.fence_fd_out = fd_out;
-
-               if (copy_to_user((void __user *)arg,
-                                               &ioctl_data,
-                                               sizeof(ioctl_data))) {
-                       DPRINT("Error, could not copy to user!!!");
-
-                       sys_close(fd_out);
-                       /* We won't be doing an increment, kref_put immediately. */
-                       kref_put(&timeline->kref, delete_timeline_obj);
-                       mutex_unlock(&global_sync_state->mutex_lock);
-                       return -EFAULT;
-               }
-
-               /* We are now about to trigger a host-side wait;
-                * accumulate on |pending_waits|. */
-               goldfish_sync_send_guestcmd(global_sync_state,
-                               CMD_TRIGGER_HOST_WAIT,
-                               ioctl_data.host_glsync_handle_in,
-                               ioctl_data.host_syncthread_handle_in,
-                               (uint64_t)(uintptr_t)(sync_context_data->timeline));
-
-               mutex_unlock(&global_sync_state->mutex_lock);
-               return 0;
-       default:
-               return -ENOTTY;
-       }
-}
-
-static const struct file_operations goldfish_sync_fops = {
-       .owner = THIS_MODULE,
-       .open = goldfish_sync_open,
-       .release = goldfish_sync_release,
-       .unlocked_ioctl = goldfish_sync_ioctl,
-       .compat_ioctl = goldfish_sync_ioctl,
-};
-
-static struct miscdevice goldfish_sync_device = {
-       .name = "goldfish_sync",
-       .fops = &goldfish_sync_fops,
-};
-
-
-static bool setup_verify_batch_cmd_addr(struct goldfish_sync_state *sync_state,
-                                                                               void *batch_addr,
-                                                                               uint32_t addr_offset,
-                                                                               uint32_t addr_offset_high)
-{
-       uint64_t batch_addr_phys;
-       uint32_t batch_addr_phys_test_lo;
-       uint32_t batch_addr_phys_test_hi;
-
-       if (!batch_addr) {
-               ERR("Could not use batch command address!");
-               return false;
-       }
-
-       batch_addr_phys = virt_to_phys(batch_addr);
-       writel((uint32_t)(batch_addr_phys),
-                       sync_state->reg_base + addr_offset);
-       writel((uint32_t)(batch_addr_phys >> 32),
-                       sync_state->reg_base + addr_offset_high);
-
-       batch_addr_phys_test_lo =
-               readl(sync_state->reg_base + addr_offset);
-       batch_addr_phys_test_hi =
-               readl(sync_state->reg_base + addr_offset_high);
-
-       if (virt_to_phys(batch_addr) !=
-                       (((uint64_t)batch_addr_phys_test_hi << 32) |
-                        batch_addr_phys_test_lo)) {
-               ERR("Invalid batch command address!");
-               return false;
-       }
-
-       return true;
-}
-
-int goldfish_sync_probe(struct platform_device *pdev)
-{
-       struct resource *ioresource;
-       struct goldfish_sync_state *sync_state = global_sync_state;
-       int status;
-
-       DTRACE();
-
-       sync_state->to_do_end = 0;
-
-       spin_lock_init(&sync_state->lock);
-       mutex_init(&sync_state->mutex_lock);
-
-       platform_set_drvdata(pdev, sync_state);
-
-       ioresource = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       if (ioresource == NULL) {
-               ERR("platform_get_resource failed");
-               return -ENODEV;
-       }
-
-       sync_state->reg_base =
-               devm_ioremap(&pdev->dev, ioresource->start, PAGE_SIZE);
-       if (sync_state->reg_base == NULL) {
-               ERR("Could not ioremap");
-               return -ENOMEM;
-       }
-
-       sync_state->irq = platform_get_irq(pdev, 0);
-       if (sync_state->irq < 0) {
-               ERR("Could not platform_get_irq");
-               return -ENODEV;
-       }
-
-       status = devm_request_irq(&pdev->dev,
-                                                       sync_state->irq,
-                                                       goldfish_sync_interrupt,
-                                                       IRQF_SHARED,
-                                                       pdev->name,
-                                                       sync_state);
-       if (status) {
-               ERR("request_irq failed");
-               return -ENODEV;
-       }
-
-       INIT_WORK(&sync_state->work_item,
-                         goldfish_sync_work_item_fn);
-
-       misc_register(&goldfish_sync_device);
-
-       /* Obtain addresses for batch send/recv of commands. */
-       {
-               struct goldfish_sync_hostcmd *batch_addr_hostcmd;
-               struct goldfish_sync_guestcmd *batch_addr_guestcmd;
-
-               batch_addr_hostcmd =
-                       devm_kzalloc(&pdev->dev, sizeof(struct goldfish_sync_hostcmd),
-                               GFP_KERNEL);
-               batch_addr_guestcmd =
-                       devm_kzalloc(&pdev->dev, sizeof(struct goldfish_sync_guestcmd),
-                               GFP_KERNEL);
-
-               if (!setup_verify_batch_cmd_addr(sync_state,
-                                       batch_addr_hostcmd,
-                                       SYNC_REG_BATCH_COMMAND_ADDR,
-                                       SYNC_REG_BATCH_COMMAND_ADDR_HIGH)) {
-                       ERR("goldfish_sync: Could not setup batch command address");
-                       return -ENODEV;
-               }
-
-               if (!setup_verify_batch_cmd_addr(sync_state,
-                                       batch_addr_guestcmd,
-                                       SYNC_REG_BATCH_GUESTCOMMAND_ADDR,
-                                       SYNC_REG_BATCH_GUESTCOMMAND_ADDR_HIGH)) {
-                       ERR("goldfish_sync: Could not setup batch guest command address");
-                       return -ENODEV;
-               }
-
-               sync_state->batch_hostcmd = batch_addr_hostcmd;
-               sync_state->batch_guestcmd = batch_addr_guestcmd;
-       }
-
-       INFO("goldfish_sync: Initialized goldfish sync device");
-
-       writel(0, sync_state->reg_base + SYNC_REG_INIT);
-
-       return 0;
-}
-
-static int goldfish_sync_remove(struct platform_device *pdev)
-{
-       struct goldfish_sync_state *sync_state = global_sync_state;
-
-       DTRACE();
-
-       misc_deregister(&goldfish_sync_device);
-       memset(sync_state, 0, sizeof(struct goldfish_sync_state));
-       return 0;
-}
-
-static const struct of_device_id goldfish_sync_of_match[] = {
-       { .compatible = "google,goldfish-sync", },
-       {},
-};
-MODULE_DEVICE_TABLE(of, goldfish_sync_of_match);
-
-static const struct acpi_device_id goldfish_sync_acpi_match[] = {
-       { "GFSH0006", 0 },
-       { },
-};
-
-MODULE_DEVICE_TABLE(acpi, goldfish_sync_acpi_match);
-
-static struct platform_driver goldfish_sync = {
-       .probe = goldfish_sync_probe,
-       .remove = goldfish_sync_remove,
-       .driver = {
-               .name = "goldfish_sync",
-               .of_match_table = goldfish_sync_of_match,
-               .acpi_match_table = ACPI_PTR(goldfish_sync_acpi_match),
-       }
-};
-
-module_platform_driver(goldfish_sync);
-
-MODULE_AUTHOR("Google, Inc.");
-MODULE_DESCRIPTION("Android QEMU Sync Driver");
-MODULE_LICENSE("GPL");
-MODULE_VERSION("1.0");
diff --git a/drivers/staging/goldfish/goldfish_sync_timeline.c b/drivers/staging/goldfish/goldfish_sync_timeline.c
new file mode 100644 (file)
index 0000000..aeccec1
--- /dev/null
@@ -0,0 +1,963 @@
+/*
+ * Copyright (C) 2016 Google, Inc.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#include <linux/fdtable.h>
+#include <linux/file.h>
+#include <linux/init.h>
+#include <linux/miscdevice.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/platform_device.h>
+
+#include <linux/interrupt.h>
+#include <linux/kref.h>
+#include <linux/spinlock.h>
+#include <linux/types.h>
+
+#include <linux/io.h>
+#include <linux/mm.h>
+#include <linux/acpi.h>
+
+#include <linux/string.h>
+
+#include <linux/fs.h>
+#include <linux/syscalls.h>
+#include <linux/sync_file.h>
+#include <linux/fence.h>
+
+#include "goldfish_sync_timeline_fence.h"
+
+#define ERR(...) printk(KERN_ERR __VA_ARGS__);
+
+#define INFO(...) printk(KERN_INFO __VA_ARGS__);
+
+#define DPRINT(...) pr_debug(__VA_ARGS__);
+
+#define DTRACE() DPRINT("%s: enter", __func__)
+
+/* The Goldfish sync driver is designed to provide a interface
+ * between the underlying host's sync device and the kernel's
+ * fence sync framework..
+ * The purpose of the device/driver is to enable lightweight
+ * creation and signaling of timelines and fences
+ * in order to synchronize the guest with host-side graphics events.
+ *
+ * Each time the interrupt trips, the driver
+ * may perform a sync operation.
+ */
+
+/* The operations are: */
+
+/* Ready signal - used to mark when irq should lower */
+#define CMD_SYNC_READY            0
+
+/* Create a new timeline. writes timeline handle */
+#define CMD_CREATE_SYNC_TIMELINE  1
+
+/* Create a fence object. reads timeline handle and time argument.
+ * Writes fence fd to the SYNC_REG_HANDLE register. */
+#define CMD_CREATE_SYNC_FENCE     2
+
+/* Increments timeline. reads timeline handle and time argument */
+#define CMD_SYNC_TIMELINE_INC     3
+
+/* Destroys a timeline. reads timeline handle */
+#define CMD_DESTROY_SYNC_TIMELINE 4
+
+/* Starts a wait on the host with
+ * the given glsync object and sync thread handle. */
+#define CMD_TRIGGER_HOST_WAIT     5
+
+/* The register layout is: */
+
+#define SYNC_REG_BATCH_COMMAND                0x00 /* host->guest batch commands */
+#define SYNC_REG_BATCH_GUESTCOMMAND           0x04 /* guest->host batch commands */
+#define SYNC_REG_BATCH_COMMAND_ADDR           0x08 /* communicate physical address of host->guest batch commands */
+#define SYNC_REG_BATCH_COMMAND_ADDR_HIGH      0x0c /* 64-bit part */
+#define SYNC_REG_BATCH_GUESTCOMMAND_ADDR      0x10 /* communicate physical address of guest->host commands */
+#define SYNC_REG_BATCH_GUESTCOMMAND_ADDR_HIGH 0x14 /* 64-bit part */
+#define SYNC_REG_INIT                         0x18 /* signals that the device has been probed */
+
+/* There is an ioctl associated with goldfish sync driver.
+ * Make it conflict with ioctls that are not likely to be used
+ * in the emulator.
+ *
+ * '@' 00-0F   linux/radeonfb.h        conflict!
+ * '@' 00-0F   drivers/video/aty/aty128fb.c    conflict!
+ */
+#define GOLDFISH_SYNC_IOC_MAGIC        '@'
+
+#define GOLDFISH_SYNC_IOC_QUEUE_WORK   _IOWR(GOLDFISH_SYNC_IOC_MAGIC, 0, struct goldfish_sync_ioctl_info)
+
+/* The above definitions (command codes, register layout, ioctl definitions)
+ * need to be in sync with the following files:
+ *
+ * Host-side (emulator):
+ * external/qemu/android/emulation/goldfish_sync.h
+ * external/qemu-android/hw/misc/goldfish_sync.c
+ *
+ * Guest-side (system image):
+ * device/generic/goldfish-opengl/system/egl/goldfish_sync.h
+ * device/generic/goldfish/ueventd.ranchu.rc
+ * platform/build/target/board/generic/sepolicy/file_contexts
+ */
+struct goldfish_sync_hostcmd {
+       /* sorted for alignment */
+       uint64_t handle;
+       uint64_t hostcmd_handle;
+       uint32_t cmd;
+       uint32_t time_arg;
+};
+
+struct goldfish_sync_guestcmd {
+       uint64_t host_command; /* uint64_t for alignment */
+       uint64_t glsync_handle;
+       uint64_t thread_handle;
+       uint64_t guest_timeline_handle;
+};
+
+#define GOLDFISH_SYNC_MAX_CMDS 64
+
+struct goldfish_sync_state {
+       char __iomem *reg_base;
+       int irq;
+
+       /* Spinlock protects |to_do| / |to_do_end|. */
+       spinlock_t lock;
+       /* |mutex_lock| protects all concurrent access
+        * to timelines for both kernel and user space. */
+       struct mutex mutex_lock;
+
+       /* Buffer holding commands issued from host. */
+       struct goldfish_sync_hostcmd to_do[GOLDFISH_SYNC_MAX_CMDS];
+       uint32_t to_do_end;
+
+       /* Addresses for the reading or writing
+        * of individual commands. The host can directly write
+        * to |batch_hostcmd| (and then this driver immediately
+        * copies contents to |to_do|). This driver either replies
+        * through |batch_hostcmd| or simply issues a
+        * guest->host command through |batch_guestcmd|.
+        */
+       struct goldfish_sync_hostcmd *batch_hostcmd;
+       struct goldfish_sync_guestcmd *batch_guestcmd;
+
+       /* Used to give this struct itself to a work queue
+        * function for executing actual sync commands. */
+       struct work_struct work_item;
+};
+
+static struct goldfish_sync_state global_sync_state[1];
+
+struct goldfish_sync_timeline_obj {
+       struct goldfish_sync_timeline *sync_tl;
+       uint32_t current_time;
+       /* We need to be careful about when we deallocate
+        * this |goldfish_sync_timeline_obj| struct.
+        * In order to ensure proper cleanup, we need to
+        * consider the triggered host-side wait that may
+        * still be in flight when the guest close()'s a
+        * goldfish_sync device's sync context fd (and
+        * destroys the |sync_tl| field above).
+        * The host-side wait may raise IRQ
+        * and tell the kernel to increment the timeline _after_
+        * the |sync_tl| has already been set to null.
+        *
+        * From observations on OpenGL apps and CTS tests, this
+        * happens at some very low probability upon context
+        * destruction or process close, but it does happen
+        * and it needs to be handled properly. Otherwise,
+        * if we clean up the surrounding |goldfish_sync_timeline_obj|
+        * too early, any |handle| field of any host->guest command
+        * might not even point to a null |sync_tl| field,
+        * but to garbage memory or even a reclaimed |sync_tl|.
+        * If we do not count such "pending waits" and kfree the object
+        * immediately upon |goldfish_sync_timeline_destroy|,
+        * we might get mysterous RCU stalls after running a long
+        * time because the garbage memory that is being read
+        * happens to be interpretable as a |spinlock_t| struct
+        * that is currently in the locked state.
+        *
+        * To track when to free the |goldfish_sync_timeline_obj|
+        * itself, we maintain a kref.
+        * The kref essentially counts the timeline itself plus
+        * the number of waits in flight. kref_init/kref_put
+        * are issued on
+        * |goldfish_sync_timeline_create|/|goldfish_sync_timeline_destroy|
+        * and kref_get/kref_put are issued on
+        * |goldfish_sync_fence_create|/|goldfish_sync_timeline_inc|.
+        *
+        * The timeline is destroyed after reference count
+        * reaches zero, which would happen after
+        * |goldfish_sync_timeline_destroy| and all pending
+        * |goldfish_sync_timeline_inc|'s are fulfilled.
+        *
+        * NOTE (1): We assume that |fence_create| and
+        * |timeline_inc| calls are 1:1, otherwise the kref scheme
+        * will not work. This is a valid assumption as long
+        * as the host-side virtual device implementation
+        * does not insert any timeline increments
+        * that we did not trigger from here.
+        *
+        * NOTE (2): The use of kref by itself requires no locks,
+        * but this does not mean everything works without locks.
+        * Related timeline operations do require a lock of some sort,
+        * or at least are not proven to work without it.
+        * In particualr, we assume that all the operations
+        * done on the |kref| field above are done in contexts where
+        * |global_sync_state->mutex_lock| is held. Do not
+        * remove that lock until everything is proven to work
+        * without it!!! */
+       struct kref kref;
+};
+
+/* We will call |delete_timeline_obj| when the last reference count
+ * of the kref is decremented. This deletes the sync
+ * timeline object along with the wrapper itself. */
+static void delete_timeline_obj(struct kref* kref) {
+       struct goldfish_sync_timeline_obj* obj =
+               container_of(kref, struct goldfish_sync_timeline_obj, kref);
+
+       goldfish_sync_timeline_put_internal(obj->sync_tl);
+       obj->sync_tl = NULL;
+       kfree(obj);
+}
+
+static uint64_t gensym_ctr;
+static void gensym(char *dst)
+{
+       sprintf(dst, "goldfish_sync:gensym:%llu", gensym_ctr);
+       gensym_ctr++;
+}
+
+/* |goldfish_sync_timeline_create| assumes that |global_sync_state->mutex_lock|
+ * is held. */
+static struct goldfish_sync_timeline_obj*
+goldfish_sync_timeline_create(void)
+{
+
+       char timeline_name[256];
+       struct goldfish_sync_timeline *res_sync_tl = NULL;
+       struct goldfish_sync_timeline_obj *res;
+
+       DTRACE();
+
+       gensym(timeline_name);
+
+       res_sync_tl = goldfish_sync_timeline_create_internal(timeline_name);
+       if (!res_sync_tl) {
+               ERR("Failed to create goldfish_sw_sync timeline.");
+               return NULL;
+       }
+
+       res = kzalloc(sizeof(struct goldfish_sync_timeline_obj), GFP_KERNEL);
+       res->sync_tl = res_sync_tl;
+       res->current_time = 0;
+       kref_init(&res->kref);
+
+       DPRINT("new timeline_obj=0x%p", res);
+       return res;
+}
+
+/* |goldfish_sync_fence_create| assumes that |global_sync_state->mutex_lock|
+ * is held. */
+static int
+goldfish_sync_fence_create(struct goldfish_sync_timeline_obj *obj,
+                                                       uint32_t val)
+{
+
+       int fd;
+       char fence_name[256];
+       struct sync_pt *syncpt = NULL;
+       struct sync_file *sync_file_obj = NULL;
+       struct goldfish_sync_timeline *tl;
+
+       DTRACE();
+
+       if (!obj) return -1;
+
+       tl = obj->sync_tl;
+
+       syncpt = goldfish_sync_pt_create_internal(
+                               tl, sizeof(struct sync_pt) + 4, val);
+       if (!syncpt) {
+               ERR("could not create sync point! "
+                       "goldfish_sync_timeline=0x%p val=%d",
+                          tl, val);
+               return -1;
+       }
+
+       fd = get_unused_fd_flags(O_CLOEXEC);
+       if (fd < 0) {
+               ERR("could not get unused fd for sync fence. "
+                       "errno=%d", fd);
+               goto err_cleanup_pt;
+       }
+
+       gensym(fence_name);
+
+       sync_file_obj = sync_file_create(&syncpt->base);
+       if (!sync_file_obj) {
+               ERR("could not create sync fence! "
+                       "goldfish_sync_timeline=0x%p val=%d sync_pt=0x%p",
+                          tl, val, syncpt);
+               goto err_cleanup_fd_pt;
+       }
+
+       DPRINT("installing sync fence into fd %d sync_file_obj=0x%p",
+                       fd, sync_file_obj);
+       fd_install(fd, sync_file_obj->file);
+       kref_get(&obj->kref);
+
+       return fd;
+
+err_cleanup_fd_pt:
+       fput(sync_file_obj->file);
+       put_unused_fd(fd);
+err_cleanup_pt:
+       fence_put(&syncpt->base);
+       return -1;
+}
+
+/* |goldfish_sync_timeline_inc| assumes that |global_sync_state->mutex_lock|
+ * is held. */
+static void
+goldfish_sync_timeline_inc(struct goldfish_sync_timeline_obj *obj, uint32_t inc)
+{
+       DTRACE();
+       /* Just give up if someone else nuked the timeline.
+        * Whoever it was won't care that it doesn't get signaled. */
+       if (!obj) return;
+
+       DPRINT("timeline_obj=0x%p", obj);
+       goldfish_sync_timeline_signal_internal(obj->sync_tl, inc);
+       DPRINT("incremented timeline. increment max_time");
+       obj->current_time += inc;
+
+       /* Here, we will end up deleting the timeline object if it
+        * turns out that this call was a pending increment after
+        * |goldfish_sync_timeline_destroy| was called. */
+       kref_put(&obj->kref, delete_timeline_obj);
+       DPRINT("done");
+}
+
+/* |goldfish_sync_timeline_destroy| assumes
+ * that |global_sync_state->mutex_lock| is held. */
+static void
+goldfish_sync_timeline_destroy(struct goldfish_sync_timeline_obj *obj)
+{
+       DTRACE();
+       /* See description of |goldfish_sync_timeline_obj| for why we
+        * should not immediately destroy |obj| */
+       kref_put(&obj->kref, delete_timeline_obj);
+}
+
+static inline void
+goldfish_sync_cmd_queue(struct goldfish_sync_state *sync_state,
+                                               uint32_t cmd,
+                                               uint64_t handle,
+                                               uint32_t time_arg,
+                                               uint64_t hostcmd_handle)
+{
+       struct goldfish_sync_hostcmd *to_add;
+
+       DTRACE();
+
+       BUG_ON(sync_state->to_do_end == GOLDFISH_SYNC_MAX_CMDS);
+
+       to_add = &sync_state->to_do[sync_state->to_do_end];
+
+       to_add->cmd = cmd;
+       to_add->handle = handle;
+       to_add->time_arg = time_arg;
+       to_add->hostcmd_handle = hostcmd_handle;
+
+       sync_state->to_do_end += 1;
+}
+
+static inline void
+goldfish_sync_hostcmd_reply(struct goldfish_sync_state *sync_state,
+                                                       uint32_t cmd,
+                                                       uint64_t handle,
+                                                       uint32_t time_arg,
+                                                       uint64_t hostcmd_handle)
+{
+       unsigned long irq_flags;
+       struct goldfish_sync_hostcmd *batch_hostcmd =
+               sync_state->batch_hostcmd;
+
+       DTRACE();
+
+       spin_lock_irqsave(&sync_state->lock, irq_flags);
+
+       batch_hostcmd->cmd = cmd;
+       batch_hostcmd->handle = handle;
+       batch_hostcmd->time_arg = time_arg;
+       batch_hostcmd->hostcmd_handle = hostcmd_handle;
+       writel(0, sync_state->reg_base + SYNC_REG_BATCH_COMMAND);
+
+       spin_unlock_irqrestore(&sync_state->lock, irq_flags);
+}
+
+static inline void
+goldfish_sync_send_guestcmd(struct goldfish_sync_state *sync_state,
+                                                       uint32_t cmd,
+                                                       uint64_t glsync_handle,
+                                                       uint64_t thread_handle,
+                                                       uint64_t timeline_handle)
+{
+       unsigned long irq_flags;
+       struct goldfish_sync_guestcmd *batch_guestcmd =
+               sync_state->batch_guestcmd;
+
+       DTRACE();
+
+       spin_lock_irqsave(&sync_state->lock, irq_flags);
+
+       batch_guestcmd->host_command = (uint64_t)cmd;
+       batch_guestcmd->glsync_handle = (uint64_t)glsync_handle;
+       batch_guestcmd->thread_handle = (uint64_t)thread_handle;
+       batch_guestcmd->guest_timeline_handle = (uint64_t)timeline_handle;
+       writel(0, sync_state->reg_base + SYNC_REG_BATCH_GUESTCOMMAND);
+
+       spin_unlock_irqrestore(&sync_state->lock, irq_flags);
+}
+
+/* |goldfish_sync_interrupt| handles IRQ raises from the virtual device.
+ * In the context of OpenGL, this interrupt will fire whenever we need
+ * to signal a fence fd in the guest, with the command
+ * |CMD_SYNC_TIMELINE_INC|.
+ * However, because this function will be called in an interrupt context,
+ * it is necessary to do the actual work of signaling off of interrupt context.
+ * The shared work queue is used for this purpose. At the end when
+ * all pending commands are intercepted by the interrupt handler,
+ * we call |schedule_work|, which will later run the actual
+ * desired sync command in |goldfish_sync_work_item_fn|.
+ */
+static irqreturn_t goldfish_sync_interrupt(int irq, void *dev_id)
+{
+
+       struct goldfish_sync_state *sync_state = dev_id;
+
+       uint32_t nextcmd;
+       uint32_t command_r;
+       uint64_t handle_rw;
+       uint32_t time_r;
+       uint64_t hostcmd_handle_rw;
+
+       int count = 0;
+
+       DTRACE();
+
+       sync_state = dev_id;
+
+       spin_lock(&sync_state->lock);
+
+       for (;;) {
+
+               readl(sync_state->reg_base + SYNC_REG_BATCH_COMMAND);
+               nextcmd = sync_state->batch_hostcmd->cmd;
+
+               if (nextcmd == 0)
+                       break;
+
+               command_r = nextcmd;
+               handle_rw = sync_state->batch_hostcmd->handle;
+               time_r = sync_state->batch_hostcmd->time_arg;
+               hostcmd_handle_rw = sync_state->batch_hostcmd->hostcmd_handle;
+
+               goldfish_sync_cmd_queue(
+                               sync_state,
+                               command_r,
+                               handle_rw,
+                               time_r,
+                               hostcmd_handle_rw);
+
+               count++;
+       }
+
+       spin_unlock(&sync_state->lock);
+
+       schedule_work(&sync_state->work_item);
+
+       return (count == 0) ? IRQ_NONE : IRQ_HANDLED;
+}
+
+/* |goldfish_sync_work_item_fn| does the actual work of servicing
+ * host->guest sync commands. This function is triggered whenever
+ * the IRQ for the goldfish sync device is raised. Once it starts
+ * running, it grabs the contents of the buffer containing the
+ * commands it needs to execute (there may be multiple, because
+ * our IRQ is active high and not edge triggered), and then
+ * runs all of them one after the other.
+ */
+static void goldfish_sync_work_item_fn(struct work_struct *input)
+{
+
+       struct goldfish_sync_state *sync_state;
+       int sync_fence_fd;
+
+       struct goldfish_sync_timeline_obj *timeline;
+       uint64_t timeline_ptr;
+
+       uint64_t hostcmd_handle;
+
+       uint32_t cmd;
+       uint64_t handle;
+       uint32_t time_arg;
+
+       struct goldfish_sync_hostcmd *todo;
+       uint32_t todo_end;
+
+       unsigned long irq_flags;
+
+       struct goldfish_sync_hostcmd to_run[GOLDFISH_SYNC_MAX_CMDS];
+       uint32_t i = 0;
+
+       sync_state = container_of(input, struct goldfish_sync_state, work_item);
+
+       mutex_lock(&sync_state->mutex_lock);
+
+       spin_lock_irqsave(&sync_state->lock, irq_flags); {
+
+               todo_end = sync_state->to_do_end;
+
+               DPRINT("num sync todos: %u", sync_state->to_do_end);
+
+               for (i = 0; i < todo_end; i++)
+                       to_run[i] = sync_state->to_do[i];
+
+               /* We expect that commands will come in at a slow enough rate
+                * so that incoming items will not be more than
+                * GOLDFISH_SYNC_MAX_CMDS.
+                *
+                * This is because the way the sync device is used,
+                * it's only for managing buffer data transfers per frame,
+                * with a sequential dependency between putting things in
+                * to_do and taking them out. Once a set of commands is
+                * queued up in to_do, the user of the device waits for
+                * them to be processed before queuing additional commands,
+                * which limits the rate at which commands come in
+                * to the rate at which we take them out here.
+                *
+                * We also don't expect more than MAX_CMDS to be issued
+                * at once; there is a correspondence between
+                * which buffers need swapping to the (display / buffer queue)
+                * to particular commands, and we don't expect there to be
+                * enough display or buffer queues in operation at once
+                * to overrun GOLDFISH_SYNC_MAX_CMDS.
+                */
+               sync_state->to_do_end = 0;
+
+       } spin_unlock_irqrestore(&sync_state->lock, irq_flags);
+
+       for (i = 0; i < todo_end; i++) {
+               DPRINT("todo index: %u", i);
+
+               todo = &to_run[i];
+
+               cmd = todo->cmd;
+
+               handle = (uint64_t)todo->handle;
+               time_arg = todo->time_arg;
+               hostcmd_handle = (uint64_t)todo->hostcmd_handle;
+
+               DTRACE();
+
+               timeline = (struct goldfish_sync_timeline_obj *)(uintptr_t)handle;
+
+               switch (cmd) {
+               case CMD_SYNC_READY:
+                       break;
+               case CMD_CREATE_SYNC_TIMELINE:
+                       DPRINT("exec CMD_CREATE_SYNC_TIMELINE: "
+                                       "handle=0x%llx time_arg=%d",
+                                       handle, time_arg);
+                       timeline = goldfish_sync_timeline_create();
+                       timeline_ptr = (uintptr_t)timeline;
+                       goldfish_sync_hostcmd_reply(sync_state, CMD_CREATE_SYNC_TIMELINE,
+                                                                               timeline_ptr,
+                                                                               0,
+                                                                               hostcmd_handle);
+                       DPRINT("sync timeline created: %p", timeline);
+                       break;
+               case CMD_CREATE_SYNC_FENCE:
+                       DPRINT("exec CMD_CREATE_SYNC_FENCE: "
+                                       "handle=0x%llx time_arg=%d",
+                                       handle, time_arg);
+                       sync_fence_fd = goldfish_sync_fence_create(timeline, time_arg);
+                       goldfish_sync_hostcmd_reply(sync_state, CMD_CREATE_SYNC_FENCE,
+                                                                               sync_fence_fd,
+                                                                               0,
+                                                                               hostcmd_handle);
+                       break;
+               case CMD_SYNC_TIMELINE_INC:
+                       DPRINT("exec CMD_SYNC_TIMELINE_INC: "
+                                       "handle=0x%llx time_arg=%d",
+                                       handle, time_arg);
+                       goldfish_sync_timeline_inc(timeline, time_arg);
+                       break;
+               case CMD_DESTROY_SYNC_TIMELINE:
+                       DPRINT("exec CMD_DESTROY_SYNC_TIMELINE: "
+                                       "handle=0x%llx time_arg=%d",
+                                       handle, time_arg);
+                       goldfish_sync_timeline_destroy(timeline);
+                       break;
+               }
+               DPRINT("Done executing sync command");
+       }
+       mutex_unlock(&sync_state->mutex_lock);
+}
+
+/* Guest-side interface: file operations */
+
+/* Goldfish sync context and ioctl info.
+ *
+ * When a sync context is created by open()-ing the goldfish sync device, we
+ * create a sync context (|goldfish_sync_context|).
+ *
+ * Currently, the only data required to track is the sync timeline itself
+ * along with the current time, which are all packed up in the
+ * |goldfish_sync_timeline_obj| field. We use a |goldfish_sync_context|
+ * as the filp->private_data.
+ *
+ * Next, when a sync context user requests that work be queued and a fence
+ * fd provided, we use the |goldfish_sync_ioctl_info| struct, which holds
+ * information about which host handles to touch for this particular
+ * queue-work operation. We need to know about the host-side sync thread
+ * and the particular host-side GLsync object. We also possibly write out
+ * a file descriptor.
+ */
+struct goldfish_sync_context {
+       struct goldfish_sync_timeline_obj *timeline;
+};
+
+struct goldfish_sync_ioctl_info {
+       uint64_t host_glsync_handle_in;
+       uint64_t host_syncthread_handle_in;
+       int fence_fd_out;
+};
+
+static int goldfish_sync_open(struct inode *inode, struct file *file)
+{
+
+       struct goldfish_sync_context *sync_context;
+
+       DTRACE();
+
+       mutex_lock(&global_sync_state->mutex_lock);
+
+       sync_context = kzalloc(sizeof(struct goldfish_sync_context), GFP_KERNEL);
+
+       if (sync_context == NULL) {
+               ERR("Creation of goldfish sync context failed!");
+               mutex_unlock(&global_sync_state->mutex_lock);
+               return -ENOMEM;
+       }
+
+       sync_context->timeline = NULL;
+
+       file->private_data = sync_context;
+
+       DPRINT("successfully create a sync context @0x%p", sync_context);
+
+       mutex_unlock(&global_sync_state->mutex_lock);
+
+       return 0;
+}
+
+static int goldfish_sync_release(struct inode *inode, struct file *file)
+{
+
+       struct goldfish_sync_context *sync_context;
+
+       DTRACE();
+
+       mutex_lock(&global_sync_state->mutex_lock);
+
+       sync_context = file->private_data;
+
+       if (sync_context->timeline)
+               goldfish_sync_timeline_destroy(sync_context->timeline);
+
+       sync_context->timeline = NULL;
+
+       kfree(sync_context);
+
+       mutex_unlock(&global_sync_state->mutex_lock);
+
+       return 0;
+}
+
+/* |goldfish_sync_ioctl| is the guest-facing interface of goldfish sync
+ * and is used in conjunction with eglCreateSyncKHR to queue up the
+ * actual work of waiting for the EGL sync command to complete,
+ * possibly returning a fence fd to the guest.
+ */
+static long goldfish_sync_ioctl(struct file *file,
+                                                               unsigned int cmd,
+                                                               unsigned long arg)
+{
+       struct goldfish_sync_context *sync_context_data;
+       struct goldfish_sync_timeline_obj *timeline;
+       int fd_out;
+       struct goldfish_sync_ioctl_info ioctl_data;
+
+       DTRACE();
+
+       sync_context_data = file->private_data;
+       fd_out = -1;
+
+       switch (cmd) {
+       case GOLDFISH_SYNC_IOC_QUEUE_WORK:
+
+               DPRINT("exec GOLDFISH_SYNC_IOC_QUEUE_WORK");
+
+               mutex_lock(&global_sync_state->mutex_lock);
+
+               if (copy_from_user(&ioctl_data,
+                                               (void __user *)arg,
+                                               sizeof(ioctl_data))) {
+                       ERR("Failed to copy memory for ioctl_data from user.");
+                       mutex_unlock(&global_sync_state->mutex_lock);
+                       return -EFAULT;
+               }
+
+               if (ioctl_data.host_syncthread_handle_in == 0) {
+                       DPRINT("Error: zero host syncthread handle!!!");
+                       mutex_unlock(&global_sync_state->mutex_lock);
+                       return -EFAULT;
+               }
+
+               if (!sync_context_data->timeline) {
+                       DPRINT("no timeline yet, create one.");
+                       sync_context_data->timeline = goldfish_sync_timeline_create();
+                       DPRINT("timeline: 0x%p", &sync_context_data->timeline);
+               }
+
+               timeline = sync_context_data->timeline;
+               fd_out = goldfish_sync_fence_create(timeline,
+                                                                                       timeline->current_time + 1);
+               DPRINT("Created fence with fd %d and current time %u (timeline: 0x%p)",
+                          fd_out,
+                          sync_context_data->timeline->current_time + 1,
+                          sync_context_data->timeline);
+
+               ioctl_data.fence_fd_out = fd_out;
+
+               if (copy_to_user((void __user *)arg,
+                                               &ioctl_data,
+                                               sizeof(ioctl_data))) {
+                       DPRINT("Error, could not copy to user!!!");
+
+                       sys_close(fd_out);
+                       /* We won't be doing an increment, kref_put immediately. */
+                       kref_put(&timeline->kref, delete_timeline_obj);
+                       mutex_unlock(&global_sync_state->mutex_lock);
+                       return -EFAULT;
+               }
+
+               /* We are now about to trigger a host-side wait;
+                * accumulate on |pending_waits|. */
+               goldfish_sync_send_guestcmd(global_sync_state,
+                               CMD_TRIGGER_HOST_WAIT,
+                               ioctl_data.host_glsync_handle_in,
+                               ioctl_data.host_syncthread_handle_in,
+                               (uint64_t)(uintptr_t)(sync_context_data->timeline));
+
+               mutex_unlock(&global_sync_state->mutex_lock);
+               return 0;
+       default:
+               return -ENOTTY;
+       }
+}
+
+static const struct file_operations goldfish_sync_fops = {
+       .owner = THIS_MODULE,
+       .open = goldfish_sync_open,
+       .release = goldfish_sync_release,
+       .unlocked_ioctl = goldfish_sync_ioctl,
+       .compat_ioctl = goldfish_sync_ioctl,
+};
+
+static struct miscdevice goldfish_sync_device = {
+       .name = "goldfish_sync",
+       .fops = &goldfish_sync_fops,
+};
+
+
+static bool setup_verify_batch_cmd_addr(struct goldfish_sync_state *sync_state,
+                                                                               void *batch_addr,
+                                                                               uint32_t addr_offset,
+                                                                               uint32_t addr_offset_high)
+{
+       uint64_t batch_addr_phys;
+       uint32_t batch_addr_phys_test_lo;
+       uint32_t batch_addr_phys_test_hi;
+
+       if (!batch_addr) {
+               ERR("Could not use batch command address!");
+               return false;
+       }
+
+       batch_addr_phys = virt_to_phys(batch_addr);
+       writel((uint32_t)(batch_addr_phys),
+                       sync_state->reg_base + addr_offset);
+       writel((uint32_t)(batch_addr_phys >> 32),
+                       sync_state->reg_base + addr_offset_high);
+
+       batch_addr_phys_test_lo =
+               readl(sync_state->reg_base + addr_offset);
+       batch_addr_phys_test_hi =
+               readl(sync_state->reg_base + addr_offset_high);
+
+       if (virt_to_phys(batch_addr) !=
+                       (((uint64_t)batch_addr_phys_test_hi << 32) |
+                        batch_addr_phys_test_lo)) {
+               ERR("Invalid batch command address!");
+               return false;
+       }
+
+       return true;
+}
+
+int goldfish_sync_probe(struct platform_device *pdev)
+{
+       struct resource *ioresource;
+       struct goldfish_sync_state *sync_state = global_sync_state;
+       int status;
+
+       DTRACE();
+
+       sync_state->to_do_end = 0;
+
+       spin_lock_init(&sync_state->lock);
+       mutex_init(&sync_state->mutex_lock);
+
+       platform_set_drvdata(pdev, sync_state);
+
+       ioresource = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       if (ioresource == NULL) {
+               ERR("platform_get_resource failed");
+               return -ENODEV;
+       }
+
+       sync_state->reg_base =
+               devm_ioremap(&pdev->dev, ioresource->start, PAGE_SIZE);
+       if (sync_state->reg_base == NULL) {
+               ERR("Could not ioremap");
+               return -ENOMEM;
+       }
+
+       sync_state->irq = platform_get_irq(pdev, 0);
+       if (sync_state->irq < 0) {
+               ERR("Could not platform_get_irq");
+               return -ENODEV;
+       }
+
+       status = devm_request_irq(&pdev->dev,
+                                                       sync_state->irq,
+                                                       goldfish_sync_interrupt,
+                                                       IRQF_SHARED,
+                                                       pdev->name,
+                                                       sync_state);
+       if (status) {
+               ERR("request_irq failed");
+               return -ENODEV;
+       }
+
+       INIT_WORK(&sync_state->work_item,
+                         goldfish_sync_work_item_fn);
+
+       misc_register(&goldfish_sync_device);
+
+       /* Obtain addresses for batch send/recv of commands. */
+       {
+               struct goldfish_sync_hostcmd *batch_addr_hostcmd;
+               struct goldfish_sync_guestcmd *batch_addr_guestcmd;
+
+               batch_addr_hostcmd =
+                       devm_kzalloc(&pdev->dev, sizeof(struct goldfish_sync_hostcmd),
+                               GFP_KERNEL);
+               batch_addr_guestcmd =
+                       devm_kzalloc(&pdev->dev, sizeof(struct goldfish_sync_guestcmd),
+                               GFP_KERNEL);
+
+               if (!setup_verify_batch_cmd_addr(sync_state,
+                                       batch_addr_hostcmd,
+                                       SYNC_REG_BATCH_COMMAND_ADDR,
+                                       SYNC_REG_BATCH_COMMAND_ADDR_HIGH)) {
+                       ERR("goldfish_sync: Could not setup batch command address");
+                       return -ENODEV;
+               }
+
+               if (!setup_verify_batch_cmd_addr(sync_state,
+                                       batch_addr_guestcmd,
+                                       SYNC_REG_BATCH_GUESTCOMMAND_ADDR,
+                                       SYNC_REG_BATCH_GUESTCOMMAND_ADDR_HIGH)) {
+                       ERR("goldfish_sync: Could not setup batch guest command address");
+                       return -ENODEV;
+               }
+
+               sync_state->batch_hostcmd = batch_addr_hostcmd;
+               sync_state->batch_guestcmd = batch_addr_guestcmd;
+       }
+
+       INFO("goldfish_sync: Initialized goldfish sync device");
+
+       writel(0, sync_state->reg_base + SYNC_REG_INIT);
+
+       return 0;
+}
+
+static int goldfish_sync_remove(struct platform_device *pdev)
+{
+       struct goldfish_sync_state *sync_state = global_sync_state;
+
+       DTRACE();
+
+       misc_deregister(&goldfish_sync_device);
+       memset(sync_state, 0, sizeof(struct goldfish_sync_state));
+       return 0;
+}
+
+static const struct of_device_id goldfish_sync_of_match[] = {
+       { .compatible = "google,goldfish-sync", },
+       {},
+};
+MODULE_DEVICE_TABLE(of, goldfish_sync_of_match);
+
+static const struct acpi_device_id goldfish_sync_acpi_match[] = {
+       { "GFSH0006", 0 },
+       { },
+};
+
+MODULE_DEVICE_TABLE(acpi, goldfish_sync_acpi_match);
+
+static struct platform_driver goldfish_sync = {
+       .probe = goldfish_sync_probe,
+       .remove = goldfish_sync_remove,
+       .driver = {
+               .name = "goldfish_sync",
+               .of_match_table = goldfish_sync_of_match,
+               .acpi_match_table = ACPI_PTR(goldfish_sync_acpi_match),
+       }
+};
+
+module_platform_driver(goldfish_sync);
+
+MODULE_AUTHOR("Google, Inc.");
+MODULE_DESCRIPTION("Android QEMU Sync Driver");
+MODULE_LICENSE("GPL");
+MODULE_VERSION("1.0");