/* Initialize signal id database. */
idr_init(&os->signalDB.idr);
-#if gcdANDROID_NATIVE_FENCE_SYNC
- /*
- * Initialize the sync point manager.
- */
-
- /* Initialize mutex. */
- gcmkONERROR(gckOS_CreateMutex(os, &os->syncPointMutex));
-
- /* Initialize sync point id database lock. */
- spin_lock_init(&os->syncPointDB.lock);
-
- /* Initialize sync point id database. */
- idr_init(&os->syncPointDB.idr);
-#endif
-
/* Create a workqueue for os timer. */
os->workqueue = create_singlethread_workqueue("galcore workqueue");
return gcvSTATUS_OK;
OnError:
-
-#if gcdANDROID_NATIVE_FENCE_SYNC
- if (os->syncPointMutex != gcvNULL)
- {
- gcmkVERIFY_OK(
- gckOS_DeleteMutex(os, os->syncPointMutex));
- }
-#endif
-
if (os->workqueue != gcvNULL)
{
destroy_workqueue(os->workqueue);
Os->paddingPage = gcvNULL;
}
-#if gcdANDROID_NATIVE_FENCE_SYNC
- /*
- * Destroy the sync point manager.
- */
-
- /* Destroy the mutex. */
- gcmkVERIFY_OK(gckOS_DeleteMutex(Os, Os->syncPointMutex));
-#endif
-
/*
* Destroy the signal manager.
*/
atomic_set(&signal->ref, 1);
#if gcdANDROID_NATIVE_FENCE_SYNC
+#if LINUX_VERSION_CODE < KERNEL_VERSION(4,9,0)
signal->timeline = gcvNULL;
+#else
+ signal->fence = gcvNULL;
+#endif
#endif
gcmkONERROR(_AllocateIntegerId(&Os->signalDB, signal, &signal->id));
gcsSIGNAL_PTR signal;
gctBOOL acquired = gcvFALSE;
#if gcdANDROID_NATIVE_FENCE_SYNC
+#if LINUX_VERSION_CODE < KERNEL_VERSION(4,9,0)
struct sync_timeline * timeline = gcvNULL;
+#else
+ struct fence * fence = gcvNULL;
+#endif
#endif
gcmkHEADER_ARG("Os=0x%X Signal=0x%X State=%d", Os, Signal, State);
complete(&signal->obj);
#if gcdANDROID_NATIVE_FENCE_SYNC
+#if LINUX_VERSION_CODE < KERNEL_VERSION(4,9,0)
timeline = signal->timeline;
+#else
+ fence = signal->fence;
+ signal->fence = NULL;
+#endif
#endif
}
else
acquired = gcvFALSE;
#if gcdANDROID_NATIVE_FENCE_SYNC
+#if LINUX_VERSION_CODE < KERNEL_VERSION(4,9,0)
/* Signal timeline. */
if (timeline)
{
sync_timeline_signal(timeline);
}
+#else
+ if (fence)
+ {
+ fence_signal(fence);
+ fence_put(fence);
+ }
+#endif
#endif
/* Success. */
}
#if gcdANDROID_NATIVE_FENCE_SYNC
+#if LINUX_VERSION_CODE < KERNEL_VERSION(4,9,0)
gceSTATUS
gckOS_CreateSyncTimeline(
IN gckOS Os,
waiter = (struct sync_fence_waiter *)kmalloc(
sizeof (struct sync_fence_waiter), gcdNOWARN | GFP_KERNEL);
+ /*
+ * schedule a callback to put the sync_fence. Otherwise after this function
+ * is returned, the caller may free it since it's signaled. Then there's
+ * be a real signal on a free'ed sync fence.
+ */
if (!waiter)
{
sync_fence_put(fence);
gcmkFOOTER();
return status;
}
+
+#else /* v4.9.0 */
+
+gceSTATUS
+gckOS_CreateSyncTimeline(
+ IN gckOS Os,
+ IN gceCORE Core,
+ OUT gctHANDLE * Timeline
+ )
+{
+ struct viv_sync_timeline *timeline;
+
+ char name[32];
+
+ snprintf(name, 32, "gccore-%u", (unsigned int) Core);
+ timeline = viv_sync_timeline_create(name, Os);
+
+ if (timeline == gcvNULL)
+ {
+ /* Out of memory. */
+ return gcvSTATUS_OUT_OF_MEMORY;
+ }
+
+ *Timeline = (gctHANDLE) timeline;
+ return gcvSTATUS_OK;
+}
+
+gceSTATUS
+gckOS_DestroySyncTimeline(
+ IN gckOS Os,
+ IN gctHANDLE Timeline
+ )
+{
+ struct viv_sync_timeline * timeline;
+
+ /* Destroy timeline. */
+ timeline = (struct viv_sync_timeline *) Timeline;
+ viv_sync_timeline_destroy(timeline);
+
+ return gcvSTATUS_OK;
+}
+
+gceSTATUS
+gckOS_CreateNativeFence(
+ IN gckOS Os,
+ IN gctHANDLE Timeline,
+ IN gctSIGNAL Signal,
+ OUT gctINT * FenceFD
+ )
+{
+ struct fence *fence = NULL;
+ struct sync_file *sync = NULL;
+ int fd;
+ struct viv_sync_timeline *timeline;
+ gcsSIGNAL_PTR signal;
+ gceSTATUS status = gcvSTATUS_OK;
+
+ /* Create fence. */
+ timeline = (struct viv_sync_timeline *) Timeline;
+
+ gcmkONERROR(
+ _QueryIntegerId(&Os->signalDB,
+ (gctUINT32)(gctUINTPTR_T)Signal,
+ (gctPOINTER)&signal));
+
+ fence = viv_fence_create(timeline, signal);
+
+ if (!fence)
+ {
+ gcmONERROR(gcvSTATUS_OUT_OF_MEMORY);
+ }
+
+ /* Create sync_file. */
+ sync = sync_file_create(fence);
+
+ if (!sync)
+ {
+ gcmONERROR(gcvSTATUS_OUT_OF_MEMORY);
+ }
+
+ /* Get a unused fd. */
+ fd = get_unused_fd_flags(O_CLOEXEC);
+
+ if (fd < 0)
+ {
+ gcmONERROR(gcvSTATUS_OUT_OF_RESOURCES);
+ }
+
+ fd_install(fd, sync->file);
+
+ *FenceFD = fd;
+ return gcvSTATUS_OK;
+
+OnError:
+ if (sync)
+ {
+ fput(sync->file);
+ }
+
+ if (fence)
+ {
+ fence_put(fence);
+ }
+
+ if (fd > 0)
+ {
+ put_unused_fd(fd);
+ }
+
+ *FenceFD = -1;
+ return status;
+}
+
+gceSTATUS
+gckOS_WaitNativeFence(
+ IN gckOS Os,
+ IN gctHANDLE Timeline,
+ IN gctINT FenceFD,
+ IN gctUINT32 Timeout
+ )
+{
+ struct fence *fence;
+ struct viv_sync_timeline *timeline;
+ gceSTATUS status = gcvSTATUS_OK;
+ unsigned int i;
+ unsigned int numFences;
+ struct fence **fences;
+ unsigned long timeout;
+
+ timeline = (struct viv_sync_timeline *) Timeline;
+
+ fence = sync_file_get_fence(FenceFD);
+
+ if (!fence)
+ {
+ gcmONERROR(gcvSTATUS_GENERIC_IO);
+ }
+
+ if (fence_is_array(fence))
+ {
+ struct fence_array *array = to_fence_array(fence);
+ fences = array->fences;
+ numFences = array->num_fences;
+ }
+ else
+ {
+ fences = &fence;
+ numFences = 1;
+ }
+
+ timeout = msecs_to_jiffies(Timeout);
+
+ for (i = 0; i < numFences; i++)
+ {
+ struct fence *f = fences[i];
+
+ if (f->context != timeline->context &&
+ !fence_is_signaled(f))
+ {
+ signed long ret;
+ ret = fence_wait_timeout(fence, 1, timeout);
+
+ if (ret == -ERESTARTSYS)
+ {
+ status = gcvSTATUS_INTERRUPTED;
+ break;
+ }
+ else if (ret <= 0)
+ {
+ status = gcvSTATUS_TIMEOUT;
+ break;
+ }
+ else
+ {
+ /* wait success. */
+ timeout -= ret;
+ }
+ }
+ }
+
+ fence_put(fence);
+
+ return gcvSTATUS_OK;
+
+OnError:
+ return status;
+}
+
+#endif /* v4.9.0 */
#endif
#if gcdSECURITY
#include <linux/module.h>
#include <linux/syscalls.h>
#include <linux/uaccess.h>
+#include <linux/slab.h>
#include "gc_hal_kernel_sync.h"
#include "gc_hal_kernel_linux.h"
-static struct sync_pt *
-viv_sync_pt_dup(
- struct sync_pt * sync_pt
- )
+#if LINUX_VERSION_CODE < KERNEL_VERSION(4,9,0)
+
+static struct sync_pt * viv_sync_pt_dup(struct sync_pt *sync_pt)
{
gceSTATUS status;
struct viv_sync_pt *pt;
struct viv_sync_pt *src;
struct viv_sync_timeline *obj;
- src = (struct viv_sync_pt *) sync_pt;
+ src = (struct viv_sync_pt *)sync_pt;
#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,17,0)
- obj = (struct viv_sync_timeline *) sync_pt_parent(sync_pt);
+ obj = (struct viv_sync_timeline *)sync_pt_parent(sync_pt);
#else
- obj = (struct viv_sync_timeline *) sync_pt->parent;
+ obj = (struct viv_sync_timeline *)sync_pt->parent;
#endif
/* Create the new sync_pt. */
gcvNULL /* (gctHANDLE) _GetProcessID() */,
&pt->signal);
- if (gcmIS_ERROR(status))
- {
+ if (gcmIS_ERROR(status)) {
sync_pt_free((struct sync_pt *)pt);
return NULL;
}
return (struct sync_pt *)pt;
}
-static int
-viv_sync_pt_has_signaled(
- struct sync_pt * sync_pt
- )
+static int viv_sync_pt_has_signaled(struct sync_pt *sync_pt)
{
gceSTATUS status;
- struct viv_sync_pt * pt;
- struct viv_sync_timeline * obj;
+ struct viv_sync_pt *pt;
+ struct viv_sync_timeline *obj;
pt = (struct viv_sync_pt *)sync_pt;
#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,17,0)
- obj = (struct viv_sync_timeline *) sync_pt_parent(sync_pt);
+ obj = (struct viv_sync_timeline *)sync_pt_parent(sync_pt);
#else
obj = (struct viv_sync_timeline *)sync_pt->parent;
#endif
status = _QuerySignal(obj->os, pt->signal);
- if (gcmIS_ERROR(status))
- {
+ if (gcmIS_ERROR(status)) {
/* Error. */
return -1;
}
return (int) status;
}
-static int
-viv_sync_pt_compare(
- struct sync_pt * a,
- struct sync_pt * b
- )
+static int viv_sync_pt_compare(struct sync_pt *a, struct sync_pt *b)
{
int ret;
- struct viv_sync_pt * pt1 = (struct viv_sync_pt *) a;
- struct viv_sync_pt * pt2 = (struct viv_sync_pt *) b;
+ struct viv_sync_pt *pt1 = (struct viv_sync_pt *)a;
+ struct viv_sync_pt *pt2 = (struct viv_sync_pt *)b;
ret = (pt1->stamp < pt2->stamp) ? -1
: (pt1->stamp == pt2->stamp) ? 0
return ret;
}
-static void
-viv_sync_pt_free(
- struct sync_pt * sync_pt
- )
+static void viv_sync_pt_free(struct sync_pt *sync_pt)
{
- struct viv_sync_pt * pt;
- struct viv_sync_timeline * obj;
+ struct viv_sync_pt *pt;
+ struct viv_sync_timeline *obj;
- pt = (struct viv_sync_pt *) sync_pt;
+ pt = (struct viv_sync_pt *)sync_pt;
#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,17,0)
- obj = (struct viv_sync_timeline *) sync_pt_parent(sync_pt);
+ obj = (struct viv_sync_timeline *)sync_pt_parent(sync_pt);
#else
- obj = (struct viv_sync_timeline *) sync_pt->parent;
+ obj = (struct viv_sync_timeline *)sync_pt->parent;
#endif
gckOS_DestroySignal(obj->os, pt->signal);
}
-static void
-viv_timeline_value_str(
- struct sync_timeline * timeline,
- char * str,
- int size
- )
+static void viv_timeline_value_str(struct sync_timeline *timeline,
+ char *str, int size)
{
- struct viv_sync_timeline * obj;
+ struct viv_sync_timeline *obj;
- obj = (struct viv_sync_timeline *) timeline;
+ obj = (struct viv_sync_timeline *)timeline;
snprintf(str, size, "stamp_%llu", obj->stamp);
}
-static void
-viv_pt_value_str(
- struct sync_pt * sync_pt,
- char * str,
- int size
- )
+static void viv_pt_value_str(struct sync_pt *sync_pt, char *str, int size)
{
- struct viv_sync_pt * pt;
+ struct viv_sync_pt *pt;
- pt = (struct viv_sync_pt *) sync_pt;
- snprintf(str, size, "signal_%lu@stamp_%llu", (unsigned long) pt->signal, pt->stamp);
+ pt = (struct viv_sync_pt *)sync_pt;
+ snprintf(str, size, "signal_%lu@stamp_%llu",
+ (unsigned long)pt->signal, pt->stamp);
}
static struct sync_timeline_ops viv_timeline_ops =
.pt_value_str = viv_pt_value_str,
};
-struct viv_sync_timeline *
-viv_sync_timeline_create(
- const char * name,
- gckOS os
- )
+struct viv_sync_timeline * viv_sync_timeline_create(const char *name, gckOS os)
{
struct viv_sync_timeline * obj;
return obj;
}
-struct sync_pt *
-viv_sync_pt_create(
- struct viv_sync_timeline * obj,
- gctSIGNAL Signal
- )
+struct sync_pt * viv_sync_pt_create(struct viv_sync_timeline *obj,
+ gctSIGNAL Signal)
{
gceSTATUS status;
- struct viv_sync_pt * pt;
+ struct viv_sync_pt *pt;
pt = (struct viv_sync_pt *)
sync_pt_create(&obj->obj, sizeof(struct viv_sync_pt));
- pt->stamp = obj->stamp++;
+ pt->stamp = obj->stamp++;
/* Dup signal. */
status = gckOS_MapSignal(obj->os,
gcvNULL /* (gctHANDLE) _GetProcessID() */,
&pt->signal);
- if (gcmIS_ERROR(status))
- {
+ if (gcmIS_ERROR(status)) {
sync_pt_free((struct sync_pt *)pt);
return NULL;
}
- return (struct sync_pt *) pt;
+ return (struct sync_pt *)pt;
+}
+
+#else /* v4.9.0 */
+
+struct viv_sync_timeline * viv_sync_timeline_create(const char *name, gckOS Os)
+{
+ struct viv_sync_timeline *timeline;
+
+ timeline = kmalloc(sizeof(struct viv_sync_timeline),
+ gcdNOWARN | GFP_KERNEL);
+
+ if (!timeline)
+ return NULL;
+
+ strncpy(timeline->name, name, sizeof(timeline->name));
+ timeline->context = fence_context_alloc(1);
+ atomic64_set(&timeline->seqno, 0);
+ timeline->os = Os;
+
+ return timeline;
+}
+
+void viv_sync_timeline_destroy(struct viv_sync_timeline *timeline)
+{
+ kfree(timeline);
+}
+
+static const char * viv_fence_get_driver_name(struct fence *fence)
+{
+ return "viv_gpu_sync";
+}
+
+static const char * viv_fence_get_timeline_name(struct fence *fence)
+{
+ struct viv_fence *f = (struct viv_fence *)fence;
+ return f->parent->name;
+}
+
+/* Same as fence_signaled. */
+static inline bool __viv_fence_signaled(struct fence *fence)
+{
+ struct viv_fence *f = (struct viv_fence *)fence;
+ struct viv_sync_timeline *timeline = f->parent;
+ gceSTATUS status;
+
+ status = _QuerySignal(timeline->os, f->signal);
+
+ return (status == gcvSTATUS_TRUE) ? true : false;
+}
+
+static bool viv_fence_enable_signaling(struct fence *fence)
+{
+ /* fence is locked already. */
+ return !__viv_fence_signaled(fence);
+}
+
+static bool viv_fence_signaled(struct fence *fence)
+{
+ /* fence could be locked, could be not. */
+ return __viv_fence_signaled(fence);
+}
+
+static void viv_fence_release(struct fence *fence)
+{
+ struct viv_fence *f = (struct viv_fence *)fence;
+ struct viv_sync_timeline *timeline = f->parent;
+
+ if (f->signal)
+ gckOS_DestroySignal(timeline->os, f->signal);
+
+ kfree(fence);
+}
+
+static struct fence_ops viv_fence_ops =
+{
+ .get_driver_name = viv_fence_get_driver_name,
+ .get_timeline_name = viv_fence_get_timeline_name,
+ .enable_signaling = viv_fence_enable_signaling,
+ .signaled = viv_fence_signaled,
+ .wait = fence_default_wait,
+ .release = viv_fence_release,
+};
+
+struct fence * viv_fence_create(struct viv_sync_timeline *timeline,
+ gcsSIGNAL *signal)
+{
+ gceSTATUS status;
+ struct viv_fence *fence;
+ struct fence *old_fence = NULL;
+ unsigned seqno;
+
+ fence = kmalloc(sizeof(struct viv_fence), gcdNOWARN | GFP_KERNEL);
+
+ if (!fence)
+ return NULL;
+
+ /* Reference signal in fence. */
+ status = gckOS_MapSignal(timeline->os, (gctSIGNAL)(uintptr_t)signal->id,
+ NULL, &fence->signal);
+
+ if (gcmIS_ERROR(status)) {
+ kfree(fence);
+ return NULL;
+ }
+
+ spin_lock_init(&fence->lock);
+
+ fence->parent = timeline;
+
+ seqno = (unsigned)atomic64_inc_return(&timeline->seqno);
+
+ fence_init((struct fence *)fence, &viv_fence_ops,
+ &fence->lock, timeline->context, seqno);
+
+ /*
+ * Reference fence in signal.
+ * Be aware of recursive reference!!
+ */
+#ifdef gcdRT_KERNEL
+ raw_spin_lock_irq(&signal->obj.wait.lock);
+#else
+ spin_lock_irq(&signal->obj.wait.lock);
+#endif
+
+ if (signal->fence) {
+ old_fence = signal->fence;
+ signal->fence = NULL;
+ }
+
+#ifdef gcdRT_KERNEL
+ raw_spin_unlock_irq(&signal->obj.wait.lock);
+#else
+ spin_unlock_irq(&signal->obj.wait.lock);
+#endif
+
+ if (!completion_done(&signal->obj)) {
+ signal->fence = (struct fence*)fence;
+ fence_get((struct fence*)fence);
+ }
+
+ if (old_fence)
+ fence_put(old_fence);
+
+ if (!signal->fence) {
+ /* Fence already signaled. */
+ gckOS_DestroySignal(timeline->os, fence->signal);
+ fence->signal = NULL;
+
+ fence_signal_locked((struct fence*)fence);
+ }
+
+ return (struct fence*)fence;
}
+#endif /* v4.9.0 */
+
#endif