Try building this on a 32 bit system. I bet that's the build warnings which Greg saw... On Wed, Jun 27, 2018 at 02:50:52PM -0700, rkir@xxxxxxxxxx wrote: > From: Roman Kiryanov <rkir@xxxxxxxxxx> > > This is kernel driver for controlling the Goldfish sync > device on the host. It is used to maintain ordering > in critical OpenGL state changes while using > GPU emulation. > > The guest open()'s the Goldfish sync device to create > a context for possibly maintaining sync timeline and fences. > There is a 1:1 correspondence between such sync contexts > and OpenGL contexts in the guest that need synchronization > (which in turn, is anything involving swapping buffers, > SurfaceFlinger, or Hardware Composer). > > The ioctl QUEUE_WORK takes a handle to a sync object > and attempts to tell the host GPU to wait on the sync object > and deal with signaling it. It possibly outputs > a fence FD on which the Android systems that use them > (GLConsumer, SurfaceFlinger, anything employing > EGL_ANDROID_native_fence_sync) can use to wait. > > Signed-off-by: Roman Kiryanov <rkir@xxxxxxxxxx> > --- > drivers/staging/goldfish/Kconfig | 7 + > drivers/staging/goldfish/Makefile | 4 + > .../staging/goldfish/goldfish_sync_timeline.c | 985 ++++++++++++++++++ > .../goldfish/goldfish_sync_timeline_fence.c | 260 +++++ > .../goldfish/goldfish_sync_timeline_fence.h | 58 ++ > include/uapi/linux/goldfish/goldfish_sync.h | 49 + > 6 files changed, 1363 insertions(+) > create mode 100644 drivers/staging/goldfish/goldfish_sync_timeline.c > create mode 100644 drivers/staging/goldfish/goldfish_sync_timeline_fence.c > create mode 100644 drivers/staging/goldfish/goldfish_sync_timeline_fence.h > create mode 100644 include/uapi/linux/goldfish/goldfish_sync.h > > diff --git a/drivers/staging/goldfish/Kconfig b/drivers/staging/goldfish/Kconfig > index 9165385df9de..59a7d26f5d3f 100644 > --- a/drivers/staging/goldfish/Kconfig > +++ b/drivers/staging/goldfish/Kconfig > @@ -4,3 +4,10 @@ config GOLDFISH_AUDIO > help > Emulated audio channel for the Goldfish Android Virtual Device > > +config GOLDFISH_SYNC > + tristate "Goldfish AVD Sync Driver" > + depends on GOLDFISH > + depends on SW_SYNC > + depends on SYNC_FILE > + ---help--- > + Emulated sync fences for the Goldfish Android Virtual Device > diff --git a/drivers/staging/goldfish/Makefile b/drivers/staging/goldfish/Makefile > index 054eeb82151e..781a81730d15 100644 > --- a/drivers/staging/goldfish/Makefile > +++ b/drivers/staging/goldfish/Makefile > @@ -3,3 +3,7 @@ > # > > obj-$(CONFIG_GOLDFISH_AUDIO) += goldfish_audio.o > + > +ccflags-y := -Idrivers/staging/android > +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_timeline.c b/drivers/staging/goldfish/goldfish_sync_timeline.c > new file mode 100644 > index 000000000000..33b17fd97499 > --- /dev/null > +++ b/drivers/staging/goldfish/goldfish_sync_timeline.c > @@ -0,0 +1,985 @@ > +/* > + * Copyright (C) 2018 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/dma-fence.h> > + > +#include <linux/goldfish.h> > + > +#include <uapi/linux/goldfish/goldfish_sync.h> > + > +#include "goldfish_sync_timeline_fence.h" > + > +/* 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: */ > +enum cmd_id { > + /* Ready signal - used to mark when irq should lower */ > + CMD_SYNC_READY = 0, > + > + /* Create a new timeline. writes timeline handle */ > + CMD_CREATE_SYNC_TIMELINE = 1, > + > + /* Create a fence object. reads timeline handle and time argument. > + * Writes fence fd to the SYNC_REG_HANDLE register. > + */ > + CMD_CREATE_SYNC_FENCE = 2, > + > + /* Increments timeline. reads timeline handle and time argument */ > + CMD_SYNC_TIMELINE_INC = 3, > + > + /* Destroys a timeline. reads timeline handle */ > + CMD_DESTROY_SYNC_TIMELINE = 4, > + > + /* Starts a wait on the host with > + * the given glsync object and sync thread handle. > + */ > + CMD_TRIGGER_HOST_WAIT = 5, > +}; > + > +/* The register layout is: */ > +enum sync_reg_id { > + /* host->guest batch commands */ > + SYNC_REG_BATCH_COMMAND = 0x00, > + > + /* guest->host batch commands */ > + SYNC_REG_BATCH_GUESTCOMMAND = 0x04, > + > + /* communicate physical address of host->guest batch commands */ > + SYNC_REG_BATCH_COMMAND_ADDR = 0x08, > + > + /* 64-bit part */ > + SYNC_REG_BATCH_COMMAND_ADDR_HIGH = 0x0c, > + > + /* communicate physical address of guest->host commands */ > + SYNC_REG_BATCH_GUESTCOMMAND_ADDR = 0x10, > + > + /* 64-bit part */ > + SYNC_REG_BATCH_GUESTCOMMAND_ADDR_HIGH = 0x14, > + > + /* signals that the device has been probed */ > + SYNC_REG_INIT = 0x18, > +}; > + > +/* 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 */ > + u64 handle; > + u64 hostcmd_handle; > + u32 cmd; > + u32 time_arg; > +}; > + > +struct goldfish_sync_guestcmd { > + u64 host_command; > + u64 glsync_handle; > + u64 thread_handle; > + u64 guest_timeline_handle; > +}; > + > +#define GOLDFISH_SYNC_MAX_CMDS 32 > + > +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]; > + u32 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; > + > + /* A pointer to struct device to use for logging */ > + struct device *dev; > +}; > + > +static struct goldfish_sync_state global_sync_state; > + > +struct goldfish_sync_timeline_obj { > + struct goldfish_sync_timeline *sync_tl; > + u32 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; ^^^^^^^^^^^^^^^^^^^ Not required. > + kfree(obj); > +} > + > +static void gensym(char *dst, int size) > +{ > + static u64 counter; > + > + snprintf(dst, size, "goldfish_sync:%s:%llu", __func__, counter); > + counter++; > +} > + > +/* |goldfish_sync_timeline_create| assumes that |global_sync_state->mutex_lock| > + * is held. > + */ > +static struct goldfish_sync_timeline_obj* > +goldfish_sync_timeline_create(struct goldfish_sync_state *sync_state) > +{ > + char timeline_name[64]; > + struct goldfish_sync_timeline *res_sync_tl = NULL; > + struct goldfish_sync_timeline_obj *res; > + > + dev_dbg(sync_state->dev, "%s:%d\n", __func__, __LINE__); > + > + gensym(timeline_name, sizeof(timeline_name)); > + > + res_sync_tl = goldfish_sync_timeline_create_internal(timeline_name); > + if (!res_sync_tl) { > + dev_err(sync_state->dev, > + "Failed to create goldfish_sw_sync timeline\n"); > + return NULL; > + } > + > + res = kzalloc(sizeof(*res), GFP_KERNEL); if (!res) { goldfish_sync_timeline_put_internal(res_sync_tl); return NULL; } > + res->sync_tl = res_sync_tl; > + res->current_time = 0; > + kref_init(&res->kref); > + > + return res; > +} > + > +/* |goldfish_sync_fence_create| assumes that |global_sync_state->mutex_lock| > + * is held. > + */ > +static int > +goldfish_sync_fence_create(struct goldfish_sync_state *sync_state, > + struct goldfish_sync_timeline_obj *obj, > + u32 val) > +{ > + int fd; > + struct sync_pt *syncpt; > + struct sync_file *sync_file_obj; > + struct goldfish_sync_timeline *tl; > + > + dev_dbg(sync_state->dev, "%s:%d\n", __func__, __LINE__); > + > + if (!obj) > + return -1; This function is returning file handles... So I guess -1 is fine. None of the callers check for error. It makes me nervous and there are no comments. > + > + tl = obj->sync_tl; > + > + syncpt = > + goldfish_sync_pt_create_internal(tl, > + sizeof(struct sync_pt) + 4, > + val); The white space is whack. syncpt = goldfish_sync_pt_create_internal(tl, sizeof(struct sync_pt) + 4, val); > + if (!syncpt) { > + dev_err(sync_state->dev, > + "Could not create sync point, val=%d\n", val); > + return -1; > + } > + > + fd = get_unused_fd_flags(O_CLOEXEC); > + if (fd < 0) { > + dev_err(sync_state->dev, > + "Could not get unused fd for sync fence, " > + "errno=%d\n", fd); > + goto err_cleanup_pt; > + } > + > + sync_file_obj = sync_file_create(&syncpt->base); > + if (!sync_file_obj) { > + dev_err(sync_state->dev, > + "Could not create sync fence! val=%d\n", val); > + goto err_cleanup_fd_pt; > + } > + > + dev_info(sync_state->dev, "Installing sync fence into fd=%d\n", fd); > + fd_install(fd, sync_file_obj->file); > + kref_get(&obj->kref); > + > + return fd; > + > +err_cleanup_fd_pt: > + put_unused_fd(fd); > +err_cleanup_pt: > + dma_fence_put(&syncpt->base); We need to free "syncpt" as well. The goldfish_sync_pt_create_internal() should have a mirror free function instead of messing around with internals like &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_state *sync_state, > + struct goldfish_sync_timeline_obj *obj, u32 inc) > +{ > + dev_dbg(sync_state->dev, "%s:%d\n", __func__, __LINE__); > + > + /* Just give up if someone else nuked the timeline. > + * Whoever it was won't care that it doesn't get signaled. > + */ > + if (!obj) > + return; > + > + goldfish_sync_timeline_signal_internal(obj->sync_tl, inc); > + dev_info(sync_state->dev, "Incremented timeline, increment max_time\n"); > + 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); > + dev_info(sync_state->dev, "done\n"); > +} > + > +/* |goldfish_sync_timeline_destroy| assumes > + * that |global_sync_state->mutex_lock| is held. > + */ > +static void > +goldfish_sync_timeline_destroy(struct goldfish_sync_state *sync_state, > + struct goldfish_sync_timeline_obj *obj) > +{ > + dev_dbg(sync_state->dev, "%s:%d\n", __func__, __LINE__); > + /* See description of |goldfish_sync_timeline_obj| for why we > + * should not immediately destroy |obj| > + */ > + kref_put(&obj->kref, delete_timeline_obj); > +} > + > +static int > +goldfish_sync_cmd_queue(struct goldfish_sync_state *sync_state, > + u32 cmd, > + u64 handle, > + u32 time_arg, > + u64 hostcmd_handle) > +{ > + u32 to_do_end = sync_state->to_do_end; We don't need the "to_do_end" variable. Just use sync_state->to_do_end directly. > + struct goldfish_sync_hostcmd *to_add; > + > + dev_dbg(sync_state->dev, "%s:%d\n", __func__, __LINE__); > + > + if (to_do_end >= GOLDFISH_SYNC_MAX_CMDS) > + return -1; I really hate -1 as an error code. Except it's not really an error code here, it just means we're full. > + > + to_add = &sync_state->to_do[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 = to_do_end + 1; > + return 0; > +} > + > +static void > +goldfish_sync_hostcmd_reply(struct goldfish_sync_state *sync_state, > + u32 cmd, > + u64 handle, > + u32 time_arg, > + u64 hostcmd_handle) > +{ > + struct goldfish_sync_hostcmd *batch_hostcmd = > + sync_state->batch_hostcmd; > + unsigned long irq_flags; > + > + dev_dbg(sync_state->dev, "%s:%d\n", __func__, __LINE__); > + > + 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 void > +goldfish_sync_send_guestcmd(struct goldfish_sync_state *sync_state, > + u32 cmd, > + u64 glsync_handle, > + u64 thread_handle, > + u64 timeline_handle) > +{ > + unsigned long irq_flags; > + struct goldfish_sync_guestcmd *batch_guestcmd = > + sync_state->batch_guestcmd; > + > + dev_dbg(sync_state->dev, "%s:%d\n", __func__, __LINE__); > + > + spin_lock_irqsave(&sync_state->lock, irq_flags); > + > + batch_guestcmd->host_command = cmd; > + batch_guestcmd->glsync_handle = glsync_handle; > + batch_guestcmd->thread_handle = thread_handle; > + batch_guestcmd->guest_timeline_handle = 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; > + int has_cmds = 0; > + > + dev_dbg(sync_state->dev, "%s:%d\n", __func__, __LINE__); > + > + spin_lock(&sync_state->lock); > + while (true) { > + struct goldfish_sync_hostcmd *batch_hostcmd; > + u32 nextcmd; > + > + readl(sync_state->reg_base + SYNC_REG_BATCH_COMMAND); > + batch_hostcmd = sync_state->batch_hostcmd; > + nextcmd = batch_hostcmd->cmd; > + > + if (nextcmd == CMD_SYNC_READY) > + break; > + > + if (goldfish_sync_cmd_queue(sync_state, > + nextcmd, > + batch_hostcmd->handle, > + batch_hostcmd->time_arg, > + batch_hostcmd->hostcmd_handle)) > + break; > + > + has_cmds = 1; > + } > + spin_unlock(&sync_state->lock); > + > + if (has_cmds) { > + schedule_work(&sync_state->work_item); > + return IRQ_HANDLED; > + } else { > + return IRQ_NONE; > + } These days checkpatch.pl --strict insists that we write it like so: if (has_cmds) { schedule_work(&sync_state->work_item); return IRQ_HANDLED; } return IRQ_NONE; > +} > + > +static u32 get_commands_todo_locked(struct goldfish_sync_state *sync_state, > + struct goldfish_sync_hostcmd *to_run) > +{ > + unsigned long irq_flags; > + u32 to_do_end; > + u32 i; > + > + spin_lock_irqsave(&sync_state->lock, irq_flags); > + to_do_end = sync_state->to_do_end; > + > + dev_info(sync_state->dev, "Num sync todos: %u\n", to_do_end); > + > + for (i = 0; i < to_do_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); > + > + return to_do_end; > +} > + > +void run_command_locked(const struct goldfish_sync_hostcmd *todo, > + struct goldfish_sync_state *sync_state) > +{ It would simplify a lot of this function if you just did this at the start: void *handle = (void *)(unsigned long)todo->handle; Btw, I think your casting u64 to pointer will cause warnings on 32 bit compiles but I haven't tested. > + switch (todo->cmd) { > + case CMD_SYNC_READY: > + break; > + > + case CMD_CREATE_SYNC_TIMELINE: > + dev_info(sync_state->dev, "CMD_CREATE_SYNC_TIMELINE\n"); > + { > + struct goldfish_sync_timeline_obj *timeline = > + goldfish_sync_timeline_create(sync_state); > + > + goldfish_sync_hostcmd_reply(sync_state, > + CMD_CREATE_SYNC_TIMELINE, > + (u64)timeline, > + 0, > + todo->hostcmd_handle); > + } > + break; > + > + case CMD_CREATE_SYNC_FENCE: > + dev_info(sync_state->dev, "CMD_CREATE_SYNC_FENCE\n"); > + { > + struct goldfish_sync_timeline_obj *timeline = > + (struct goldfish_sync_timeline_obj *) > + todo->handle; > + > + int sync_fence_fd = > + goldfish_sync_fence_create(sync_state, > + timeline, > + todo->time_arg); > + > + goldfish_sync_hostcmd_reply(sync_state, > + CMD_CREATE_SYNC_FENCE, > + sync_fence_fd, > + 0, > + todo->hostcmd_handle); > + } > + break; We don't really need to dev_info() since most of this can be found with ftrace... We could pull it in a tab. Then it would look like this: case CMD_CREATE_SYNC_FENCE: { int fd = goldfish_sync_fence_create(sync_state, handle, todo->time_arg); goldfish_sync_hostcmd_reply(sync_state, CMD_CREATE_SYNC_FENCE, fd, 0, todo->hostcmd_handle); break; } case CMD_SYNC_TIMELINE_INC: { > + > + case CMD_SYNC_TIMELINE_INC: > + dev_info(sync_state->dev, "CMD_SYNC_TIMELINE_INC\n"); > + { > + struct goldfish_sync_timeline_obj *timeline = > + (struct goldfish_sync_timeline_obj *) > + todo->handle; > + > + goldfish_sync_timeline_inc(sync_state, > + timeline, > + todo->time_arg); > + } > + break; > + > + case CMD_DESTROY_SYNC_TIMELINE: > + dev_info(sync_state->dev, "CMD_DESTROY_SYNC_TIMELINE\n"); > + { > + struct goldfish_sync_timeline_obj *timeline = > + (struct goldfish_sync_timeline_obj *) > + todo->handle; > + > + goldfish_sync_timeline_destroy(sync_state, timeline); > + } > + break; > + > + default: > + dev_err(sync_state->dev, "Unexpected command: %u\n", todo->cmd); > + break; > + } > + > + dev_info(sync_state->dev, "Done executing sync command\n"); This should be dev_dbg() or deleted. > +} > + > +void run_commands_locked(struct goldfish_sync_state *sync_state, > + struct goldfish_sync_hostcmd *to_run, > + u32 to_do_end) > +{ > + u32 i; > + > + for (i = 0; i < to_do_end; ++i) { > + dev_info(sync_state->dev, "todo index: %u\n", i); Too spammy. > + run_command_locked(&to_run[i], sync_state); > + } > +} > + > +/* |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 = > + container_of(input, struct goldfish_sync_state, work_item); > + struct goldfish_sync_hostcmd to_run[GOLDFISH_SYNC_MAX_CMDS]; > + u32 to_do_end; > + > + mutex_lock(&sync_state->mutex_lock); > + to_do_end = get_commands_todo_locked(sync_state, to_run); > + run_commands_locked(sync_state, to_run, to_do_end); > + 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; > +}; > + > +static int goldfish_sync_open(struct inode *inode, struct file *file) > +{ > + struct goldfish_sync_context *sync_context; > + > + dev_dbg(global_sync_state.dev, "%s:%d\n", __func__, __LINE__); > + > + mutex_lock(&global_sync_state.mutex_lock); > + > + sync_context = kzalloc(sizeof(*sync_context), GFP_ATOMIC); > + if (!sync_context) { > + mutex_unlock(&global_sync_state.mutex_lock); > + return -ENOMEM; > + } > + > + sync_context->timeline = NULL; > + > + file->private_data = 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; > + > + dev_dbg(global_sync_state.dev, "%s:%d\n", __func__, __LINE__); > + > + mutex_lock(&global_sync_state.mutex_lock); > + > + sync_context = file->private_data; > + > + if (sync_context->timeline) > + goldfish_sync_timeline_destroy(&global_sync_state, > + sync_context->timeline); > + > + 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 device *dev = global_sync_state.dev; > + struct goldfish_sync_context *sync_context_data; > + struct goldfish_sync_timeline_obj *timeline; > + struct goldfish_sync_ioctl_info ioctl_data; > + int fd_out; > + u32 current_time; > + > + sync_context_data = file->private_data; > + fd_out = -1; No need to initialize this to a bogus value. > + > + switch (cmd) { > + case GOLDFISH_SYNC_IOC_QUEUE_WORK: > + dev_info(dev, "exec GOLDFISH_SYNC_IOC_QUEUE_WORK\n"); > + > + mutex_lock(&global_sync_state.mutex_lock); > + > + if (copy_from_user(&ioctl_data, > + (void __user *)arg, > + sizeof(ioctl_data))) { > + dev_err(dev, > + "Failed to copy memory for ioctl_data from user\n"); Copy from user shouldn't be able to trigger a dev_err() or the user can DoS /var/log/messages. Please check all the dev_info() output as well. > + mutex_unlock(&global_sync_state.mutex_lock); > + return -EFAULT; > + } > + > + if (ioctl_data.host_syncthread_handle_in == 0) { > + dev_err(dev, "Error: zero host syncthread handle\n"); > + mutex_unlock(&global_sync_state.mutex_lock); > + return -EFAULT; -EINVAL; > + } > + > + timeline = sync_context_data->timeline; > + if (!timeline) { > + dev_info(dev, "No timeline yet, create one\n"); > + timeline = goldfish_sync_timeline_create(&global_sync_state); > + sync_context_data->timeline = timeline; > + } > + > + current_time = timeline->current_time + 1; > + > + fd_out = goldfish_sync_fence_create(&global_sync_state, > + timeline, > + current_time); > + dev_info(dev, "Created fence with fd %d and current time %u\n", > + fd_out, current_time); > + > + ioctl_data.fence_fd_out = fd_out; > + > + if (copy_to_user((void __user *)arg, > + &ioctl_data, > + sizeof(ioctl_data))) { > + dev_err(dev, "copy_to_user failed\n"); > + > + ksys_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, > + (u64)timeline); > + > + mutex_unlock(&global_sync_state.mutex_lock); > + return 0; > + > + default: > + dev_err(dev, "Unexpected ioctl command: %u\n", cmd); > + 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, > + u32 addr_offset, > + u32 addr_offset_high) > +{ > + u64 batch_addr_phys; > + u64 batch_addr_phys_test; These variables are too long so you end up hitting the 80 char limit. > + > + if (!batch_addr) { > + dev_err(sync_state->dev, > + "Could not use batch command address\n"); > + return false; > + } > + > + batch_addr_phys = virt_to_phys(batch_addr); > + gf_write_u64(batch_addr_phys, > + sync_state->reg_base + addr_offset, > + sync_state->reg_base + addr_offset_high); Get rid of the batch_addr_phys variable. gf_write_u64(virt_to_phys(batch_addr), sync_state->reg_base + addr_offset, sync_state->reg_base + addr_offset_high); > + > + batch_addr_phys_test = > + gf_read_u64(sync_state->reg_base + addr_offset, > + sync_state->reg_base + addr_offset_high); > + > + if (virt_to_phys(batch_addr) != batch_addr_phys_test) { > + dev_err(sync_state->dev, "Invalid batch command address\n"); > + return false; > + } > + > + return true; > +} > + > +int goldfish_sync_probe(struct platform_device *pdev) > +{ > + struct goldfish_sync_state *sync_state = &global_sync_state; > + struct device *dev = &pdev->dev; > + struct resource *ioresource; > + int status; > + > + dev_dbg(sync_state->dev, "%s:%d\n", __func__, __LINE__); > + > + sync_state->dev = dev; > + 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) { > + dev_err(dev, "platform_get_resource failed\n"); > + return -ENODEV; > + } > + > + sync_state->reg_base = > + devm_ioremap(dev, ioresource->start, PAGE_SIZE); This can fit on one line. It's exactly 80 char. > + if (!sync_state->reg_base) { > + dev_err(dev, "devm_ioremap failed\n"); > + return -ENOMEM; > + } > + > + sync_state->irq = platform_get_irq(pdev, 0); > + if (sync_state->irq < 0) { > + dev_err(dev, "platform_get_irq failed\n"); > + return -ENODEV; > + } > + > + status = devm_request_irq(dev, > + sync_state->irq, > + goldfish_sync_interrupt, > + IRQF_SHARED, > + pdev->name, > + sync_state); > + if (status) { > + dev_err(dev, "devm_request_irq failed\n"); > + return -ENODEV; Preserve the error code "return status;". > + } > + > + 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; Put these at the start of the function and pull everything back a tab. > + > + batch_addr_hostcmd = > + devm_kzalloc(dev, sizeof(*batch_addr_hostcmd), > + GFP_KERNEL); > + batch_addr_guestcmd = > + devm_kzalloc(dev, sizeof(*batch_addr_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)) { > + dev_err(dev, "Could not setup batch command address\n"); We need to misc_deregister(&goldfish_sync_device); on these error paths. > + return -ENODEV; > + } > + > + if (!setup_verify_batch_cmd_addr(sync_state, > + batch_addr_guestcmd, > + SYNC_REG_BATCH_GUESTCOMMAND_ADDR, > + SYNC_REG_BATCH_GUESTCOMMAND_ADDR_HIGH)) { > + dev_err(dev, "Could not setup batch guest command address\n"); > + return -ENODEV; > + } > + > + sync_state->batch_hostcmd = batch_addr_hostcmd; > + sync_state->batch_guestcmd = batch_addr_guestcmd; > + } > + > + dev_info(dev, "goldfish_sync: Initialized goldfish sync device\n"); > + > + writel(0, sync_state->reg_base + SYNC_REG_INIT); > + > + return 0; > +} > + regards, dan carpenter _______________________________________________ devel mailing list devel@xxxxxxxxxxxxxxxxxxxxxx http://driverdev.linuxdriverproject.org/mailman/listinfo/driverdev-devel