aboutsummaryrefslogtreecommitdiff
path: root/drivers/gpu/host1x/intr.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/gpu/host1x/intr.c')
-rw-r--r--drivers/gpu/host1x/intr.c41
1 files changed, 29 insertions, 12 deletions
diff --git a/drivers/gpu/host1x/intr.c b/drivers/gpu/host1x/intr.c
index 26f3c741d085..965ba21818b1 100644
--- a/drivers/gpu/host1x/intr.c
+++ b/drivers/gpu/host1x/intr.c
@@ -13,6 +13,7 @@
#include <trace/events/host1x.h>
#include "channel.h"
#include "dev.h"
+#include "fence.h"
#include "intr.h"
/* Wait list management */
@@ -105,7 +106,6 @@ static void action_submit_complete(struct host1x_waitlist *waiter)
/* Add nr_completed to trace */
trace_host1x_channel_submit_complete(dev_name(channel->dev),
waiter->count, waiter->thresh);
-
}
static void action_wakeup(struct host1x_waitlist *waiter)
@@ -122,12 +122,20 @@ static void action_wakeup_interruptible(struct host1x_waitlist *waiter)
wake_up_interruptible(wq);
}
+static void action_signal_fence(struct host1x_waitlist *waiter)
+{
+ struct host1x_syncpt_fence *f = waiter->data;
+
+ host1x_fence_signal(f);
+}
+
typedef void (*action_handler)(struct host1x_waitlist *waiter);
static const action_handler action_handlers[HOST1X_INTR_ACTION_COUNT] = {
action_submit_complete,
action_wakeup,
action_wakeup_interruptible,
+ action_signal_fence,
};
static void run_handlers(struct list_head completed[HOST1X_INTR_ACTION_COUNT])
@@ -236,25 +244,37 @@ int host1x_intr_add_action(struct host1x *host, struct host1x_syncpt *syncpt,
host1x_hw_intr_enable_syncpt_intr(host, syncpt->id);
}
- spin_unlock(&syncpt->intr.lock);
-
if (ref)
*ref = waiter;
+
+ spin_unlock(&syncpt->intr.lock);
+
return 0;
}
-void host1x_intr_put_ref(struct host1x *host, unsigned int id, void *ref)
+void host1x_intr_put_ref(struct host1x *host, unsigned int id, void *ref,
+ bool flush)
{
struct host1x_waitlist *waiter = ref;
struct host1x_syncpt *syncpt;
- while (atomic_cmpxchg(&waiter->state, WLS_PENDING, WLS_CANCELLED) ==
- WLS_REMOVED)
- schedule();
+ atomic_cmpxchg(&waiter->state, WLS_PENDING, WLS_CANCELLED);
syncpt = host->syncpt + id;
- (void)process_wait_list(host, syncpt,
- host1x_syncpt_load(host->syncpt + id));
+
+ spin_lock(&syncpt->intr.lock);
+ if (atomic_cmpxchg(&waiter->state, WLS_CANCELLED, WLS_HANDLED) ==
+ WLS_CANCELLED) {
+ list_del(&waiter->list);
+ kref_put(&waiter->refcount, waiter_release);
+ }
+ spin_unlock(&syncpt->intr.lock);
+
+ if (flush) {
+ /* Wait until any concurrently executing handler has finished. */
+ while (atomic_read(&waiter->state) != WLS_HANDLED)
+ schedule();
+ }
kref_put(&waiter->refcount, waiter_release);
}
@@ -277,14 +297,11 @@ int host1x_intr_init(struct host1x *host, unsigned int irq_sync)
"host1x_sp_%02u", id);
}
- host1x_intr_start(host);
-
return 0;
}
void host1x_intr_deinit(struct host1x *host)
{
- host1x_intr_stop(host);
}
void host1x_intr_start(struct host1x *host)