mirror of
git://nv-tegra.nvidia.com/linux-nv-oot.git
synced 2025-12-22 09:11:26 +03:00
gpu: host1x: Timestamp syncpoint wait completions
Collect CLOCK_MONOTONIC timestamps in the interrupt handler when a syncpoint wait completes, and report it back in dma_fences and syncpoint wait UAPI. Signed-off-by: Mikko Perttunen <mperttunen@nvidia.com> Change-Id: I9f783833698df7d96c99c9ffef3205aa82adceb5 Reviewed-on: https://git-master.nvidia.com/r/c/linux-nvidia/+/2801167 Reviewed-by: Jonathan Hunter <jonathanh@nvidia.com> Reviewed-by: svc_kernel_abi <svc_kernel_abi@nvidia.com> GVS: Gerrit_Virtual_Submit <buildbot_gerritrpt@nvidia.com>
This commit is contained in:
committed by
Laxman Dewangan
parent
f6865a3c2d
commit
a351c7681e
@@ -72,7 +72,7 @@ const struct dma_fence_ops host1x_syncpt_fence_ops = {
|
||||
.enable_signaling = host1x_syncpt_fence_enable_signaling,
|
||||
};
|
||||
|
||||
void host1x_fence_signal(struct host1x_syncpt_fence *f)
|
||||
void host1x_fence_signal(struct host1x_syncpt_fence *f, ktime_t ts)
|
||||
{
|
||||
if (atomic_xchg(&f->signaling, 1)) {
|
||||
/*
|
||||
@@ -91,7 +91,7 @@ void host1x_fence_signal(struct host1x_syncpt_fence *f)
|
||||
dma_fence_put(&f->base);
|
||||
}
|
||||
|
||||
dma_fence_signal_locked(&f->base);
|
||||
dma_fence_signal_timestamp_locked(&f->base, ts);
|
||||
dma_fence_put(&f->base);
|
||||
}
|
||||
|
||||
|
||||
@@ -25,6 +25,6 @@ struct host1x_fence_list {
|
||||
struct list_head list;
|
||||
};
|
||||
|
||||
void host1x_fence_signal(struct host1x_syncpt_fence *fence);
|
||||
void host1x_fence_signal(struct host1x_syncpt_fence *fence, ktime_t ts);
|
||||
|
||||
#endif
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/irq.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/timekeeping.h>
|
||||
|
||||
#include "../intr.h"
|
||||
#include "../dev.h"
|
||||
@@ -18,6 +19,9 @@ static irqreturn_t syncpt_thresh_isr(int irq, void *dev_id)
|
||||
struct host1x *host = dev_id;
|
||||
unsigned long reg;
|
||||
unsigned int i, id;
|
||||
ktime_t ts;
|
||||
|
||||
ts = ktime_get();
|
||||
|
||||
for (i = 0; i < DIV_ROUND_UP(host->info->nb_pts, 32); i++) {
|
||||
reg = host1x_sync_readl(host,
|
||||
@@ -29,7 +33,7 @@ static irqreturn_t syncpt_thresh_isr(int irq, void *dev_id)
|
||||
HOST1X_SYNC_SYNCPT_THRESH_CPU0_INT_STATUS(i));
|
||||
|
||||
for_each_set_bit(id, ®, 32)
|
||||
host1x_intr_handle_interrupt(host, i * 32 + id);
|
||||
host1x_intr_handle_interrupt(host, i * 32 + id, ts);
|
||||
}
|
||||
|
||||
return IRQ_HANDLED;
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
#include <linux/dma-direction.h>
|
||||
#include <linux/dma-fence.h>
|
||||
#include <linux/spinlock.h>
|
||||
#include <linux/timekeeping.h>
|
||||
#include <linux/types.h>
|
||||
|
||||
enum host1x_class {
|
||||
@@ -211,6 +212,8 @@ u32 host1x_syncpt_read_max(struct host1x_syncpt *sp);
|
||||
u32 host1x_syncpt_read(struct host1x_syncpt *sp);
|
||||
int host1x_syncpt_incr(struct host1x_syncpt *sp);
|
||||
u32 host1x_syncpt_incr_max(struct host1x_syncpt *sp, u32 incrs);
|
||||
int host1x_syncpt_wait_ts(struct host1x_syncpt *sp, u32 thresh, long timeout,
|
||||
u32 *value, ktime_t *ts);
|
||||
int host1x_syncpt_wait(struct host1x_syncpt *sp, u32 thresh, long timeout,
|
||||
u32 *value);
|
||||
struct host1x_syncpt *host1x_syncpt_request(struct host1x_client *client,
|
||||
|
||||
@@ -72,7 +72,7 @@ bool host1x_intr_remove_fence(struct host1x *host, struct host1x_syncpt_fence *f
|
||||
return true;
|
||||
}
|
||||
|
||||
void host1x_intr_handle_interrupt(struct host1x *host, unsigned int id)
|
||||
void host1x_intr_handle_interrupt(struct host1x *host, unsigned int id, ktime_t ts)
|
||||
{
|
||||
struct host1x_syncpt *sp = &host->syncpt[id];
|
||||
struct host1x_syncpt_fence *fence, *tmp;
|
||||
@@ -89,7 +89,7 @@ void host1x_intr_handle_interrupt(struct host1x *host, unsigned int id)
|
||||
}
|
||||
|
||||
list_del_init(&fence->list);
|
||||
host1x_fence_signal(fence);
|
||||
host1x_fence_signal(fence, ts);
|
||||
}
|
||||
|
||||
/* Re-enable interrupt if necessary */
|
||||
|
||||
@@ -8,6 +8,8 @@
|
||||
#ifndef __HOST1X_INTR_H
|
||||
#define __HOST1X_INTR_H
|
||||
|
||||
#include <linux/timekeeping.h>
|
||||
|
||||
struct host1x;
|
||||
struct host1x_syncpt_fence;
|
||||
|
||||
@@ -23,7 +25,7 @@ void host1x_intr_start(struct host1x *host);
|
||||
/* Disable host1x sync point interrupt */
|
||||
void host1x_intr_stop(struct host1x *host);
|
||||
|
||||
void host1x_intr_handle_interrupt(struct host1x *host, unsigned int id);
|
||||
void host1x_intr_handle_interrupt(struct host1x *host, unsigned int id, ktime_t ts);
|
||||
|
||||
void host1x_intr_add_fence_locked(struct host1x *host, struct host1x_syncpt_fence *fence);
|
||||
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
#include <linux/device.h>
|
||||
#include <linux/dma-fence.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/timekeeping.h>
|
||||
|
||||
#include <trace/events/host1x.h>
|
||||
|
||||
@@ -211,14 +212,15 @@ int host1x_syncpt_incr(struct host1x_syncpt *sp)
|
||||
EXPORT_SYMBOL(host1x_syncpt_incr);
|
||||
|
||||
/**
|
||||
* host1x_syncpt_wait() - wait for a syncpoint to reach a given value
|
||||
* host1x_syncpt_wait_ts() - wait for a syncpoint to reach a given value
|
||||
* @sp: host1x syncpoint
|
||||
* @thresh: threshold
|
||||
* @timeout: maximum time to wait for the syncpoint to reach the given value
|
||||
* @value: return location for the syncpoint value
|
||||
* @ts: return location for completion timestamp
|
||||
*/
|
||||
int host1x_syncpt_wait(struct host1x_syncpt *sp, u32 thresh, long timeout,
|
||||
u32 *value)
|
||||
int host1x_syncpt_wait_ts(struct host1x_syncpt *sp, u32 thresh, long timeout, u32 *value,
|
||||
ktime_t *ts)
|
||||
{
|
||||
struct dma_fence *fence;
|
||||
long wait_err;
|
||||
@@ -227,6 +229,8 @@ int host1x_syncpt_wait(struct host1x_syncpt *sp, u32 thresh, long timeout,
|
||||
|
||||
if (value)
|
||||
*value = host1x_syncpt_load(sp);
|
||||
if (ts)
|
||||
*ts = ktime_get();
|
||||
|
||||
if (host1x_syncpt_is_expired(sp, thresh))
|
||||
return 0;
|
||||
@@ -243,10 +247,13 @@ int host1x_syncpt_wait(struct host1x_syncpt *sp, u32 thresh, long timeout,
|
||||
wait_err = dma_fence_wait_timeout(fence, true, timeout);
|
||||
if (wait_err == 0)
|
||||
host1x_fence_cancel(fence);
|
||||
dma_fence_put(fence);
|
||||
|
||||
if (value)
|
||||
*value = host1x_syncpt_load(sp);
|
||||
if (ts)
|
||||
*ts = fence->timestamp;
|
||||
|
||||
dma_fence_put(fence);
|
||||
|
||||
if (wait_err == 0)
|
||||
return -EAGAIN;
|
||||
@@ -255,6 +262,19 @@ int host1x_syncpt_wait(struct host1x_syncpt *sp, u32 thresh, long timeout,
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(host1x_syncpt_wait_ts);
|
||||
|
||||
/**
|
||||
* host1x_syncpt_wait() - wait for a syncpoint to reach a given value
|
||||
* @sp: host1x syncpoint
|
||||
* @thresh: threshold
|
||||
* @timeout: maximum time to wait for the syncpoint to reach the given value
|
||||
* @value: return location for the syncpoint value
|
||||
*/
|
||||
int host1x_syncpt_wait(struct host1x_syncpt *sp, u32 thresh, long timeout, u32 *value)
|
||||
{
|
||||
return host1x_syncpt_wait_ts(sp, thresh, timeout, value, NULL);
|
||||
}
|
||||
EXPORT_SYMBOL(host1x_syncpt_wait);
|
||||
|
||||
/*
|
||||
|
||||
Reference in New Issue
Block a user