Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 1cbd16b5 authored by Lingfeng Yang's avatar Lingfeng Yang Committed by Dmitry Shmidt
Browse files

ANDROID: goldfish_sync: upgrade to new fence sync api



goldfish_sync requires the following modifications
to bring it up:

- Copy and integrate goldfish_sync version of
sw_sync, from out of dma-buf driver.
- Don't delete timelines by itself; rely on put

Change-Id: Ie88d506955dbf5c8532281f122471dc7b1c0bccb
Signed-off-by: default avatarLingfeng Yang <lfy@google.com>
parent e37704d2
Loading
Loading
Loading
Loading
+2 −0
Original line number Diff line number Diff line
@@ -7,6 +7,8 @@ config GOLDFISH_AUDIO
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

+1 −0
Original line number Diff line number Diff line
@@ -8,4 +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
obj-$(CONFIG_GOLDFISH_SYNC) += goldfish_sync.o
+40 −64
Original line number Diff line number Diff line
@@ -30,10 +30,13 @@
#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 "sw_sync.h"
#include "sync.h"
#include "goldfish_sync_timeline_fence.h"

#define ERR(...) printk(KERN_ERR __VA_ARGS__);

@@ -45,13 +48,13 @@

/* The Goldfish sync driver is designed to provide a interface
 * between the underlying host's sync device and the kernel's
 * sw_sync.
 * 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 sw_sync operation.
 * may perform a sync operation.
 */

/* The operations are: */
@@ -158,7 +161,7 @@ struct goldfish_sync_state {
static struct goldfish_sync_state global_sync_state[1];

struct goldfish_sync_timeline_obj {
	struct sw_sync_timeline *sw_sync_tl;
	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.
@@ -166,10 +169,10 @@ struct goldfish_sync_timeline_obj {
	 * 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 |sw_sync_tl| field above).
	 * destroys the |sync_tl| field above).
	 * The host-side wait may raise IRQ
	 * and tell the kernel to increment the timeline _after_
	 * the |sw_sync_tl| has already been set to null.
	 * 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
@@ -177,8 +180,8 @@ struct goldfish_sync_timeline_obj {
	 * 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 |sw_sync_tl| field,
	 * but to garbage memory or even a reclaimed |sw_sync_tl|.
	 * 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
@@ -220,14 +223,14 @@ struct goldfish_sync_timeline_obj {
};

/* We will call |delete_timeline_obj| when the last reference count
 * of the kref is decremented. This deletes the sw_sync
 * 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);

	sync_timeline_destroy(&obj->sw_sync_tl->obj);
	obj->sw_sync_tl = NULL;
	goldfish_sync_timeline_put_internal(obj->sync_tl);
	obj->sync_tl = NULL;
	kfree(obj);
}

@@ -245,21 +248,21 @@ goldfish_sync_timeline_create(void)
{

	char timeline_name[256];
	struct sw_sync_timeline *res_sync_tl = NULL;
	struct goldfish_sync_timeline *res_sync_tl = NULL;
	struct goldfish_sync_timeline_obj *res;

	DTRACE();

	gensym(timeline_name);

	res_sync_tl = sw_sync_timeline_create(timeline_name);
	res_sync_tl = goldfish_sync_timeline_create_internal(timeline_name);
	if (!res_sync_tl) {
		ERR("Failed to create sw_sync timeline.");
		ERR("Failed to create goldfish_sw_sync timeline.");
		return NULL;
	}

	res = kzalloc(sizeof(struct goldfish_sync_timeline_obj), GFP_KERNEL);
	res->sw_sync_tl = res_sync_tl;
	res->sync_tl = res_sync_tl;
	res->current_time = 0;
	kref_init(&res->kref);

@@ -277,19 +280,20 @@ goldfish_sync_fence_create(struct goldfish_sync_timeline_obj *obj,
	int fd;
	char fence_name[256];
	struct sync_pt *syncpt = NULL;
	struct sync_fence *sync_obj = NULL;
	struct sw_sync_timeline *tl;
	struct sync_file *sync_file_obj = NULL;
	struct goldfish_sync_timeline *tl;

	DTRACE();

	if (!obj) return -1;

	tl = obj->sw_sync_tl;
	tl = obj->sync_tl;

	syncpt = sw_sync_pt_create(tl, val);
	syncpt = goldfish_sync_pt_create_internal(
				tl, sizeof(struct sync_pt) + 4, val);
	if (!syncpt) {
		ERR("could not create sync point! "
			"sync_timeline=0x%p val=%d",
			"goldfish_sync_timeline=0x%p val=%d",
			   tl, val);
		return -1;
	}
@@ -303,24 +307,26 @@ goldfish_sync_fence_create(struct goldfish_sync_timeline_obj *obj,

	gensym(fence_name);

	sync_obj = sync_fence_create(fence_name, syncpt);
	if (!sync_obj) {
	sync_file_obj = sync_file_create(&syncpt->base);
	if (!sync_file_obj) {
		ERR("could not create sync fence! "
			"sync_timeline=0x%p val=%d sync_pt=0x%p",
			"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_obj=0x%p", fd, sync_obj);
	sync_fence_install(sync_obj, fd);
	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:
	sync_pt_free(syncpt);
	fence_put(&syncpt->base);
	return -1;
}

@@ -335,7 +341,7 @@ goldfish_sync_timeline_inc(struct goldfish_sync_timeline_obj *obj, uint32_t inc)
	if (!obj) return;

	DPRINT("timeline_obj=0x%p", obj);
	sw_sync_timeline_inc(obj->sw_sync_tl, inc);
	goldfish_sync_timeline_signal_internal(obj->sync_tl, inc);
	DPRINT("incremented timeline. increment max_time");
	obj->current_time += inc;

@@ -847,7 +853,8 @@ int goldfish_sync_probe(struct platform_device *pdev)
		return -ENODEV;
	}

	sync_state->reg_base = devm_ioremap(&pdev->dev, ioresource->start, PAGE_SIZE);
	sync_state->reg_base =
		devm_ioremap(&pdev->dev, ioresource->start, PAGE_SIZE);
	if (sync_state->reg_base == NULL) {
		ERR("Could not ioremap");
		return -ENOMEM;
@@ -880,9 +887,11 @@ int goldfish_sync_probe(struct platform_device *pdev)
		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),
		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),
		batch_addr_guestcmd =
			devm_kzalloc(&pdev->dev, sizeof(struct goldfish_sync_guestcmd),
				GFP_KERNEL);

		if (!setup_verify_batch_cmd_addr(sync_state,
@@ -952,36 +961,3 @@ MODULE_AUTHOR("Google, Inc.");
MODULE_DESCRIPTION("Android QEMU Sync Driver");
MODULE_LICENSE("GPL");
MODULE_VERSION("1.0");

/* This function is only to run a basic test of sync framework.
 * It creates a timeline and fence object whose signal point is at 1.
 * The timeline is incremented, and we use the sync framework's
 * sync_fence_wait on that fence object. If everything works out,
 * we should not hang in the wait and return immediately.
 * There is no way to explicitly run this test yet, but it
 * can be used by inserting it at the end of goldfish_sync_probe.
 */
void test_kernel_sync(void)
{
	struct goldfish_sync_timeline_obj *test_timeline;
	int test_fence_fd;

	DTRACE();

	DPRINT("test sw_sync");

	test_timeline = goldfish_sync_timeline_create();
	DPRINT("sw_sync_timeline_create -> 0x%p", test_timeline);

	test_fence_fd = goldfish_sync_fence_create(test_timeline, 1);
	DPRINT("sync_fence_create -> %d", test_fence_fd);

	DPRINT("incrementing test timeline");
	goldfish_sync_timeline_inc(test_timeline, 1);

	DPRINT("test waiting (should NOT hang)");
	sync_fence_wait(
			sync_fence_fdget(test_fence_fd), -1);

	DPRINT("test waiting (afterward)");
}
+254 −0
Original line number Diff line number Diff line
#include <linux/slab.h>
#include <linux/fs.h>
#include <linux/syscalls.h>
#include <linux/sync_file.h>
#include <linux/fence.h>

#include "goldfish_sync_timeline_fence.h"

/*
 * Timeline-based sync for Goldfish Sync
 * Based on "Sync File validation framework"
 * (drivers/dma-buf/sw_sync.c)
 *
 * Copyright (C) 2017 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.
 *
 */

/**
 * struct goldfish_sync_timeline - sync object
 * @kref:		reference count on fence.
 * @name:		name of the goldfish_sync_timeline. Useful for debugging
 * @child_list_head:	list of children sync_pts for this goldfish_sync_timeline
 * @child_list_lock:	lock protecting @child_list_head and fence.status
 * @active_list_head:	list of active (unsignaled/errored) sync_pts
 */
struct goldfish_sync_timeline {
	struct kref		kref;
	char			name[32];

	/* protected by child_list_lock */
	u64			context;
	int			value;

	struct list_head	child_list_head;
	spinlock_t		child_list_lock;

	struct list_head	active_list_head;
};

static inline struct goldfish_sync_timeline *fence_parent(struct fence *fence)
{
	return container_of(fence->lock, struct goldfish_sync_timeline,
				child_list_lock);
}

static const struct fence_ops goldfish_sync_timeline_fence_ops;

static inline struct sync_pt *goldfish_sync_fence_to_sync_pt(struct fence *fence)
{
	if (fence->ops != &goldfish_sync_timeline_fence_ops)
		return NULL;
	return container_of(fence, struct sync_pt, base);
}

/**
 * goldfish_sync_timeline_create_internal() - creates a sync object
 * @name:	sync_timeline name
 *
 * Creates a new sync_timeline. Returns the sync_timeline object or NULL in
 * case of error.
 */
struct goldfish_sync_timeline
*goldfish_sync_timeline_create_internal(const char *name)
{
	struct goldfish_sync_timeline *obj;

	obj = kzalloc(sizeof(*obj), GFP_KERNEL);
	if (!obj)
		return NULL;

	kref_init(&obj->kref);
	obj->context = fence_context_alloc(1);
	strlcpy(obj->name, name, sizeof(obj->name));

	INIT_LIST_HEAD(&obj->child_list_head);
	INIT_LIST_HEAD(&obj->active_list_head);
	spin_lock_init(&obj->child_list_lock);

	return obj;
}

static void goldfish_sync_timeline_free_internal(struct kref *kref)
{
	struct goldfish_sync_timeline *obj =
		container_of(kref, struct goldfish_sync_timeline, kref);

	kfree(obj);
}

static void goldfish_sync_timeline_get_internal(
					struct goldfish_sync_timeline *obj)
{
	kref_get(&obj->kref);
}

void goldfish_sync_timeline_put_internal(struct goldfish_sync_timeline *obj)
{
	kref_put(&obj->kref, goldfish_sync_timeline_free_internal);
}

/**
 * goldfish_sync_timeline_signal() -
 * signal a status change on a goldfish_sync_timeline
 * @obj:	sync_timeline to signal
 * @inc:	num to increment on timeline->value
 *
 * A sync implementation should call this any time one of it's fences
 * has signaled or has an error condition.
 */
void goldfish_sync_timeline_signal_internal(struct goldfish_sync_timeline *obj,
											unsigned int inc)
{
	unsigned long flags;
	struct sync_pt *pt, *next;

	spin_lock_irqsave(&obj->child_list_lock, flags);

	obj->value += inc;

	list_for_each_entry_safe(pt, next, &obj->active_list_head,
				 active_list) {
		if (fence_is_signaled_locked(&pt->base))
			list_del_init(&pt->active_list);
	}

	spin_unlock_irqrestore(&obj->child_list_lock, flags);
}

/**
 * goldfish_sync_pt_create_internal() - creates a sync pt
 * @parent:	fence's parent sync_timeline
 * @size:	size to allocate for this pt
 * @inc:	value of the fence
 *
 * Creates a new sync_pt as a child of @parent.  @size bytes will be
 * allocated allowing for implementation specific data to be kept after
 * the generic sync_timeline struct. Returns the sync_pt object or
 * NULL in case of error.
 */
struct sync_pt *goldfish_sync_pt_create_internal(
					struct goldfish_sync_timeline *obj, int size,
				 	unsigned int value)
{
	unsigned long flags;
	struct sync_pt *pt;

	if (size < sizeof(*pt))
		return NULL;

	pt = kzalloc(size, GFP_KERNEL);
	if (!pt)
		return NULL;

	spin_lock_irqsave(&obj->child_list_lock, flags);
	goldfish_sync_timeline_get_internal(obj);
	fence_init(&pt->base, &goldfish_sync_timeline_fence_ops, &obj->child_list_lock,
		   obj->context, value);
	list_add_tail(&pt->child_list, &obj->child_list_head);
	INIT_LIST_HEAD(&pt->active_list);
	spin_unlock_irqrestore(&obj->child_list_lock, flags);
	return pt;
}

static const char *goldfish_sync_timeline_fence_get_driver_name(
						struct fence *fence)
{
	return "sw_sync";
}

static const char *goldfish_sync_timeline_fence_get_timeline_name(
						struct fence *fence)
{
	struct goldfish_sync_timeline *parent = fence_parent(fence);

	return parent->name;
}

static void goldfish_sync_timeline_fence_release(struct fence *fence)
{
	struct sync_pt *pt = goldfish_sync_fence_to_sync_pt(fence);
	struct goldfish_sync_timeline *parent = fence_parent(fence);
	unsigned long flags;

	spin_lock_irqsave(fence->lock, flags);
	list_del(&pt->child_list);
	if (!list_empty(&pt->active_list))
		list_del(&pt->active_list);
	spin_unlock_irqrestore(fence->lock, flags);

	goldfish_sync_timeline_put_internal(parent);
	fence_free(fence);
}

static bool goldfish_sync_timeline_fence_signaled(struct fence *fence)
{
	struct goldfish_sync_timeline *parent = fence_parent(fence);

	return (fence->seqno > parent->value) ? false : true;
}

static bool goldfish_sync_timeline_fence_enable_signaling(struct fence *fence)
{
	struct sync_pt *pt = goldfish_sync_fence_to_sync_pt(fence);
	struct goldfish_sync_timeline *parent = fence_parent(fence);

	if (goldfish_sync_timeline_fence_signaled(fence))
		return false;

	list_add_tail(&pt->active_list, &parent->active_list_head);
	return true;
}

static void goldfish_sync_timeline_fence_disable_signaling(struct fence *fence)
{
	struct sync_pt *pt = container_of(fence, struct sync_pt, base);

	list_del_init(&pt->active_list);
}

static void goldfish_sync_timeline_fence_value_str(struct fence *fence,
					char *str, int size)
{
	snprintf(str, size, "%d", fence->seqno);
}

static void goldfish_sync_timeline_fence_timeline_value_str(
				struct fence *fence,
				char *str, int size)
{
	struct goldfish_sync_timeline *parent = fence_parent(fence);

	snprintf(str, size, "%d", parent->value);
}

static const struct fence_ops goldfish_sync_timeline_fence_ops = {
	.get_driver_name = goldfish_sync_timeline_fence_get_driver_name,
	.get_timeline_name = goldfish_sync_timeline_fence_get_timeline_name,
	.enable_signaling = goldfish_sync_timeline_fence_enable_signaling,
	.disable_signaling = goldfish_sync_timeline_fence_disable_signaling,
	.signaled = goldfish_sync_timeline_fence_signaled,
	.wait = fence_default_wait,
	.release = goldfish_sync_timeline_fence_release,
	.fence_value_str = goldfish_sync_timeline_fence_value_str,
	.timeline_value_str = goldfish_sync_timeline_fence_timeline_value_str,
};
+58 −0
Original line number Diff line number Diff line
#include <linux/sync_file.h>
#include <linux/fence.h>

/**
 * struct sync_pt - sync_pt object
 * @base: base fence object
 * @child_list: sync timeline child's list
 * @active_list: sync timeline active child's list
 */
struct sync_pt {
	struct fence base;
	struct list_head child_list;
	struct list_head active_list;
};

/**
 * goldfish_sync_timeline_create_internal() - creates a sync object
 * @name:	goldfish_sync_timeline name
 *
 * Creates a new goldfish_sync_timeline.
 * Returns the goldfish_sync_timeline object or NULL in case of error.
 */
struct goldfish_sync_timeline
*goldfish_sync_timeline_create_internal(const char *name);

/**
 * goldfish_sync_pt_create_internal() - creates a sync pt
 * @parent:	fence's parent goldfish_sync_timeline
 * @size:	size to allocate for this pt
 * @inc:	value of the fence
 *
 * Creates a new sync_pt as a child of @parent.  @size bytes will be
 * allocated allowing for implementation specific data to be kept after
 * the generic sync_timeline struct. Returns the sync_pt object or
 * NULL in case of error.
 */
struct sync_pt
*goldfish_sync_pt_create_internal(struct goldfish_sync_timeline *obj,
									int size, unsigned int value);

/**
 * goldfish_sync_timeline_signal_internal() -
 * signal a status change on a sync_timeline
 * @obj:	goldfish_sync_timeline to signal
 * @inc:	num to increment on timeline->value
 *
 * A sync implementation should call this any time one of it's fences
 * has signaled or has an error condition.
 */
void goldfish_sync_timeline_signal_internal(struct goldfish_sync_timeline *obj,
											unsigned int inc);

/**
 * goldfish_sync_timeline_put_internal() - dec refcount of a sync_timeline
 * and clean up memory if it was the last ref.
 * @obj:	goldfish_sync_timeline to decref
 */
void goldfish_sync_timeline_put_internal(struct goldfish_sync_timeline *obj);