From 74bcc029c6ab942f252477a74102877f7d093388 Mon Sep 17 00:00:00 2001 From: mcampbellsmith Date: Wed, 20 Nov 2013 22:34:44 +1100 Subject: mali: bulk import of r3p2-01rel3 drivers from i9300-update12 Courtesy of a similar commit from OMNI ROM. Requires updated mali blobs Change-Id: I9ee55b653b57b7c390f8e0e8cd4fc068f1c751c3 --- drivers/gpu/mali400/r3p2/mali/linux/mali_sync.c | 273 ++++++++++++++++++++++++ 1 file changed, 273 insertions(+) create mode 100644 drivers/gpu/mali400/r3p2/mali/linux/mali_sync.c (limited to 'drivers/gpu/mali400/r3p2/mali/linux/mali_sync.c') diff --git a/drivers/gpu/mali400/r3p2/mali/linux/mali_sync.c b/drivers/gpu/mali400/r3p2/mali/linux/mali_sync.c new file mode 100644 index 0000000..6293610 --- /dev/null +++ b/drivers/gpu/mali400/r3p2/mali/linux/mali_sync.c @@ -0,0 +1,273 @@ +/* + * Copyright (C) 2012 ARM Limited. All rights reserved. + * + * This program is free software and is provided to you under the terms of the GNU General Public License version 2 + * as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence. + * + * A copy of the licence is included with the program, and can also be obtained from Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +/** + * @file mali_sync.c + * + */ + +#include +#include +#include + +#include "mali_osk.h" +#include "mali_kernel_common.h" + +struct mali_sync_timeline +{ + struct sync_timeline timeline; + atomic_t counter; + atomic_t signalled; +}; + +struct mali_sync_pt +{ + struct sync_pt pt; + u32 order; + s32 error; + struct timer_list timer; +}; + +static void mali_sync_timed_pt_timeout(unsigned long data); + +static inline struct mali_sync_timeline *to_mali_sync_timeline(struct sync_timeline *timeline) +{ + return container_of(timeline, struct mali_sync_timeline, timeline); +} + +static inline struct mali_sync_pt *to_mali_sync_pt(struct sync_pt *pt) +{ + return container_of(pt, struct mali_sync_pt, pt); +} + +static struct sync_pt *timeline_dup(struct sync_pt *pt) +{ + struct mali_sync_pt *mpt = to_mali_sync_pt(pt); + struct mali_sync_pt *new_mpt; + struct sync_pt *new_pt = sync_pt_create(pt->parent, sizeof(struct mali_sync_pt)); + + if (!new_pt) + { + return NULL; + } + + new_mpt = to_mali_sync_pt(new_pt); + new_mpt->order = mpt->order; + + return new_pt; + +} + +static int timeline_has_signaled(struct sync_pt *pt) +{ + struct mali_sync_pt *mpt = to_mali_sync_pt(pt); + struct mali_sync_timeline *mtl = to_mali_sync_timeline(pt->parent); + long diff; + + if (0 != mpt->error) + { + return mpt->error; + } + + diff = atomic_read(&mtl->signalled) - mpt->order; + + return diff >= 0; +} + +static int timeline_compare(struct sync_pt *a, struct sync_pt *b) +{ + struct mali_sync_pt *ma = container_of(a, struct mali_sync_pt, pt); + struct mali_sync_pt *mb = container_of(b, struct mali_sync_pt, pt); + + long diff = ma->order - mb->order; + + if (diff < 0) + { + return -1; + } + else if (diff == 0) + { + return 0; + } + else + { + return 1; + } +} + +static void timeline_free_pt(struct sync_pt *pt) +{ + struct mali_sync_pt *mpt = to_mali_sync_pt(pt); + + if (mpt->timer.function == mali_sync_timed_pt_timeout) + { + del_timer_sync(&mpt->timer); + } +} + +static void timeline_print_tl(struct seq_file *s, struct sync_timeline *sync_timeline) +{ + struct mali_sync_timeline *mtl = to_mali_sync_timeline(sync_timeline); + + seq_printf(s, "%u, %u", atomic_read(&mtl->signalled), atomic_read(&mtl->counter)); +} + +static void timeline_print_pt(struct seq_file *s, struct sync_pt *sync_pt) +{ + struct mali_sync_pt *mpt = to_mali_sync_pt(sync_pt); + + seq_printf(s, "%u", mpt->order); + +} + +static struct sync_timeline_ops mali_timeline_ops = { + .driver_name = "Mali", + .dup = timeline_dup, + .has_signaled = timeline_has_signaled, + .compare = timeline_compare, + .free_pt = timeline_free_pt, + .print_obj = timeline_print_tl, + .print_pt = timeline_print_pt +}; + +int mali_sync_timeline_is_ours(struct sync_timeline *timeline) +{ + return (timeline->ops == &mali_timeline_ops); +} + +struct sync_timeline *mali_sync_timeline_alloc(const char * name) +{ + struct sync_timeline *tl; + struct mali_sync_timeline *mtl; + + tl = sync_timeline_create(&mali_timeline_ops, + sizeof(struct mali_sync_timeline), name); + if (!tl) + { + return NULL; + } + + /* Set the counter in our private struct */ + mtl = to_mali_sync_timeline(tl); + atomic_set(&mtl->counter, 0); + atomic_set(&mtl->signalled, 0); + + return tl; +} + +struct sync_pt *mali_sync_pt_alloc(struct sync_timeline *parent) +{ + struct sync_pt *pt = sync_pt_create(parent, sizeof(struct mali_sync_pt)); + struct mali_sync_timeline *mtl = to_mali_sync_timeline(parent); + struct mali_sync_pt *mpt; + + if (!pt) + { + return NULL; + } + + mpt = to_mali_sync_pt(pt); + mpt->order = atomic_inc_return(&mtl->counter); + mpt->error = 0; + + return pt; +} + +static void mali_sync_timed_pt_timeout(unsigned long data) +{ + struct sync_pt *pt = (struct sync_pt *)data; + + MALI_DEBUG_ASSERT_POINTER(pt); + + mali_sync_signal_pt(pt, -ETIME); +} + +struct sync_pt *mali_sync_timed_pt_alloc(struct sync_timeline *parent) +{ + struct sync_pt *pt; + struct mali_sync_pt *mpt; + const u32 timeout = msecs_to_jiffies(MALI_SYNC_TIMED_FENCE_TIMEOUT); + + pt = mali_sync_pt_alloc(parent); + if (NULL == pt) return NULL; + mpt = to_mali_sync_pt(pt); + + init_timer(&mpt->timer); + + mpt->timer.function = mali_sync_timed_pt_timeout; + mpt->timer.data = (unsigned long)pt; + mpt->timer.expires = jiffies + timeout; + + add_timer(&mpt->timer); + + return pt; +} + +/* + * Returns 0 if sync_pt has been committed and are ready for use, -ETIME if + * timeout already happened and the fence has been signalled. + * + * If an error occurs the sync point can not be used. + */ +int mali_sync_timed_commit(struct sync_pt *pt) +{ + struct mali_sync_pt *mpt = to_mali_sync_pt(pt); + int ret; + + if (!mali_sync_timeline_is_ours(pt->parent)) + { + return -EINVAL; + } + + /* Stop timer */ + ret = del_timer_sync(&mpt->timer); + + if (0 == ret) + { + return -ETIME; + } + + MALI_DEBUG_ASSERT(0 == timeline_has_signaled(pt)); + + return 0; +} + +void mali_sync_signal_pt(struct sync_pt *pt, int error) +{ + struct mali_sync_pt *mpt = to_mali_sync_pt(pt); + struct mali_sync_timeline *mtl = to_mali_sync_timeline(pt->parent); + int signalled; + long diff; + + if (0 != error) + { + MALI_DEBUG_ASSERT(0 > error); + mpt->error = error; + } + + do { + + signalled = atomic_read(&mtl->signalled); + + diff = signalled - mpt->order; + + if (diff > 0) + { + /* The timeline is already at or ahead of this point. This should not happen unless userspace + * has been signalling fences out of order, so warn but don't violate the sync_pt API. + * The warning is only in debug builds to prevent a malicious user being able to spam dmesg. + */ + MALI_DEBUG_PRINT_ERROR(("Sync points were triggerd in a different order to allocation!\n")); + return; + } + } while (atomic_cmpxchg(&mtl->signalled, signalled, mpt->order) != signalled); + + sync_timeline_signal(pt->parent); +} -- cgit v1.1