123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181 |
- /*
- *
- * (C) COPYRIGHT 2012-2015 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.
- *
- */
- #ifdef CONFIG_SYNC
- #include <linux/seq_file.h>
- #include "sync.h"
- #include <mali_kbase.h>
- #include <mali_kbase_sync.h>
- struct mali_sync_timeline {
- struct sync_timeline timeline;
- atomic_t counter;
- atomic_t signalled;
- };
- struct mali_sync_pt {
- struct sync_pt pt;
- int order;
- int result;
- };
- static struct mali_sync_timeline *to_mali_sync_timeline(struct sync_timeline *timeline)
- {
- return container_of(timeline, struct mali_sync_timeline, timeline);
- }
- static 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(sync_pt_parent(pt), sizeof(struct mali_sync_pt));
- if (!new_pt)
- return NULL;
- new_mpt = to_mali_sync_pt(new_pt);
- new_mpt->order = mpt->order;
- new_mpt->result = mpt->result;
- 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(sync_pt_parent(pt));
- int result = mpt->result;
- int diff = atomic_read(&mtl->signalled) - mpt->order;
- if (diff >= 0)
- return (result < 0) ? result : 1;
- return 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);
- int diff = ma->order - mb->order;
- if (diff == 0)
- return 0;
- return (diff < 0) ? -1 : 1;
- }
- static void timeline_value_str(struct sync_timeline *timeline, char *str,
- int size)
- {
- struct mali_sync_timeline *mtl = to_mali_sync_timeline(timeline);
- snprintf(str, size, "%d", atomic_read(&mtl->signalled));
- }
- static void pt_value_str(struct sync_pt *pt, char *str, int size)
- {
- struct mali_sync_pt *mpt = to_mali_sync_pt(pt);
- snprintf(str, size, "%d(%d)", mpt->order, mpt->result);
- }
- static struct sync_timeline_ops mali_timeline_ops = {
- .driver_name = "Mali",
- .dup = timeline_dup,
- .has_signaled = timeline_has_signaled,
- .compare = timeline_compare,
- .timeline_value_str = timeline_value_str,
- .pt_value_str = pt_value_str,
- };
- int kbase_sync_timeline_is_ours(struct sync_timeline *timeline)
- {
- return timeline->ops == &mali_timeline_ops;
- }
- struct sync_timeline *kbase_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 *kbase_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->result = 0;
- return pt;
- }
- void kbase_sync_signal_pt(struct sync_pt *pt, int result)
- {
- struct mali_sync_pt *mpt = to_mali_sync_pt(pt);
- struct mali_sync_timeline *mtl = to_mali_sync_timeline(sync_pt_parent(pt));
- int signalled;
- int diff;
- mpt->result = result;
- 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.
- */
- #ifdef CONFIG_MALI_DEBUG
- pr_err("Fences were triggered in a different order to allocation!");
- #endif
- return;
- }
- } while (atomic_cmpxchg(&mtl->signalled, signalled, mpt->order) != signalled);
- }
- #endif // ifdef CONFIG_SYNC
|