summaryrefslogtreecommitdiff
path: root/drivers/video
diff options
context:
space:
mode:
authorArto Merilainen <amerilainen@nvidia.com>2012-09-26 16:05:18 +0300
committerDan Willemsen <dwillemsen@nvidia.com>2013-09-14 13:04:11 -0700
commit8e2a4e9c836c56652965d6950b830809f0eda89f (patch)
tree96f771d3a75aeea76070e04f17d861031de2acf5 /drivers/video
parentbb0b53207c647152d278895e909d19da30267411 (diff)
video: tegra: host: "SP wait more extended" ioctl
This patch adds WAITMEX ioctl for querying extended information about syncpoint completion (i.e. accurate time of ISR). Bug 1051737 Change-Id: I434e04c3b0fd37fe84ff8788458dd75e86fe691d Signed-off-by: Arto Merilainen <amerilainen@nvidia.com> Reviewed-on: http://git-master/r/138969 Reviewed-by: Simone Willett <swillett@nvidia.com> Tested-by: Simone Willett <swillett@nvidia.com>
Diffstat (limited to 'drivers/video')
-rw-r--r--drivers/video/tegra/dc/dsi.c2
-rw-r--r--drivers/video/tegra/dc/ext/dev.c2
-rw-r--r--drivers/video/tegra/host/host1x/host1x.c30
-rw-r--r--drivers/video/tegra/host/host1x/host1x_intr.c2
-rw-r--r--drivers/video/tegra/host/nvhost_intr.c16
-rw-r--r--drivers/video/tegra/host/nvhost_intr.h2
-rw-r--r--drivers/video/tegra/host/nvhost_syncpt.c17
-rw-r--r--drivers/video/tegra/host/nvhost_syncpt.h4
8 files changed, 66 insertions, 9 deletions
diff --git a/drivers/video/tegra/dc/dsi.c b/drivers/video/tegra/dc/dsi.c
index 7f16aed3713b..fadb7cb9d429 100644
--- a/drivers/video/tegra/dc/dsi.c
+++ b/drivers/video/tegra/dc/dsi.c
@@ -442,7 +442,7 @@ static int __maybe_unused tegra_dsi_syncpt(struct tegra_dc_dsi_data *dsi)
tegra_dsi_writel(dsi, val, DSI_INCR_SYNCPT);
ret = nvhost_syncpt_wait_timeout_ext(dsi->dc->ndev, dsi->syncpt_id,
- dsi->syncpt_val + 1, MAX_SCHEDULE_TIMEOUT, NULL);
+ dsi->syncpt_val + 1, MAX_SCHEDULE_TIMEOUT, NULL, NULL);
if (ret < 0) {
dev_err(&dsi->dc->ndev->dev, "DSI sync point failure\n");
goto fail;
diff --git a/drivers/video/tegra/dc/ext/dev.c b/drivers/video/tegra/dc/ext/dev.c
index d264365d9c03..7580c02f8bfb 100644
--- a/drivers/video/tegra/dc/ext/dev.c
+++ b/drivers/video/tegra/dc/ext/dev.c
@@ -280,7 +280,7 @@ static int tegra_dc_ext_set_windowattr(struct tegra_dc_ext *ext,
nvhost_syncpt_wait_timeout_ext(ext->dc->ndev,
flip_win->attr.pre_syncpt_id,
flip_win->attr.pre_syncpt_val,
- msecs_to_jiffies(500), NULL);
+ msecs_to_jiffies(500), NULL, NULL);
}
if (err < 0)
diff --git a/drivers/video/tegra/host/host1x/host1x.c b/drivers/video/tegra/host/host1x/host1x.c
index e71fdc7a03a0..6a2084b8015b 100644
--- a/drivers/video/tegra/host/host1x/host1x.c
+++ b/drivers/video/tegra/host/host1x/host1x.c
@@ -136,13 +136,38 @@ static int nvhost_ioctl_ctrl_syncpt_waitex(struct nvhost_ctrl_userctx *ctx,
timeout = (u32)msecs_to_jiffies(args->timeout);
err = nvhost_syncpt_wait_timeout(&ctx->dev->syncpt, args->id,
- args->thresh, timeout, &args->value);
+ args->thresh, timeout, &args->value,
+ NULL);
trace_nvhost_ioctl_ctrl_syncpt_wait(args->id, args->thresh,
args->timeout, args->value, err);
return err;
}
+static int nvhost_ioctl_ctrl_syncpt_waitmex(struct nvhost_ctrl_userctx *ctx,
+ struct nvhost_ctrl_syncpt_waitmex_args *args)
+{
+ u32 timeout;
+ int err;
+ struct timespec ts;
+ if (args->id >= nvhost_syncpt_nb_pts(&ctx->dev->syncpt))
+ return -EINVAL;
+ if (args->timeout == NVHOST_NO_TIMEOUT)
+ timeout = MAX_SCHEDULE_TIMEOUT;
+ else
+ timeout = (u32)msecs_to_jiffies(args->timeout);
+
+ err = nvhost_syncpt_wait_timeout(&ctx->dev->syncpt, args->id,
+ args->thresh, timeout, &args->value,
+ &ts);
+ args->tv_sec = ts.tv_sec;
+ args->tv_nsec = ts.tv_nsec;
+ trace_nvhost_ioctl_ctrl_syncpt_wait(args->id, args->thresh,
+ args->timeout, args->value, err);
+
+ return err;
+}
+
static int nvhost_ioctl_ctrl_module_mutex(struct nvhost_ctrl_userctx *ctx,
struct nvhost_ctrl_module_mutex_args *args)
{
@@ -308,6 +333,9 @@ static long nvhost_ctrlctl(struct file *filp,
case NVHOST_IOCTL_CTRL_SYNCPT_READ_MAX:
err = nvhost_ioctl_ctrl_syncpt_read_max(priv, (void *)buf);
break;
+ case NVHOST_IOCTL_CTRL_SYNCPT_WAITMEX:
+ err = nvhost_ioctl_ctrl_syncpt_waitmex(priv, (void *)buf);
+ break;
default:
err = -ENOTTY;
break;
diff --git a/drivers/video/tegra/host/host1x/host1x_intr.c b/drivers/video/tegra/host/host1x/host1x_intr.c
index e63d32f73652..ca3c931566c9 100644
--- a/drivers/video/tegra/host/host1x/host1x_intr.c
+++ b/drivers/video/tegra/host/host1x/host1x_intr.c
@@ -22,6 +22,7 @@
#include <linux/interrupt.h>
#include <linux/irq.h>
#include <linux/io.h>
+#include <linux/ktime.h>
#include "nvhost_intr.h"
#include "dev.h"
@@ -53,6 +54,7 @@ static irqreturn_t syncpt_thresh_cascade_isr(int irq, void *dev_id)
for_each_set_bit(id, &reg, BITS_PER_LONG) {
struct nvhost_intr_syncpt *sp =
intr->syncpt + (i * BITS_PER_LONG + id);
+ ktime_get_ts(&sp->isr_recv);
t20_intr_syncpt_thresh_isr(sp);
queue_work(intr->wq, &sp->work);
}
diff --git a/drivers/video/tegra/host/nvhost_intr.c b/drivers/video/tegra/host/nvhost_intr.c
index b7dff78a1a60..e6008cd3f7c2 100644
--- a/drivers/video/tegra/host/nvhost_intr.c
+++ b/drivers/video/tegra/host/nvhost_intr.c
@@ -37,6 +37,7 @@ struct nvhost_waitlist {
u32 thresh;
enum nvhost_intr_action action;
atomic_t state;
+ struct timespec isr_recv;
void *data;
int count;
};
@@ -53,6 +54,16 @@ static void waiter_release(struct kref *kref)
kfree(container_of(kref, struct nvhost_waitlist, refcount));
}
+int nvhost_intr_release_time(void *ref, struct timespec *ts)
+{
+ struct nvhost_waitlist *waiter = ref;
+ if (atomic_read(&waiter->state) == WLS_PENDING)
+ return -EBUSY;
+
+ *ts = waiter->isr_recv;
+ return 0;
+}
+
/**
* add a waiter to a waiter queue, sorted by threshold
* returns true if it was added at the head of the queue
@@ -78,6 +89,7 @@ static bool add_waiter_to_queue(struct nvhost_waitlist *waiter,
* and gather all completed waiters into lists by actions
*/
static void remove_completed_waiters(struct list_head *head, u32 sync,
+ struct timespec isr_recv,
struct list_head completed[NVHOST_INTR_ACTION_COUNT])
{
struct list_head *dest;
@@ -87,6 +99,7 @@ static void remove_completed_waiters(struct list_head *head, u32 sync,
if ((s32)(waiter->thresh - sync) > 0)
break;
+ waiter->isr_recv = isr_recv;
dest = completed + waiter->action;
/* consolidate submit cleanups */
@@ -204,7 +217,8 @@ static int process_wait_list(struct nvhost_intr *intr,
spin_lock(&syncpt->lock);
- remove_completed_waiters(&syncpt->wait_head, threshold, completed);
+ remove_completed_waiters(&syncpt->wait_head, threshold,
+ syncpt->isr_recv, completed);
empty = list_empty(&syncpt->wait_head);
if (empty)
diff --git a/drivers/video/tegra/host/nvhost_intr.h b/drivers/video/tegra/host/nvhost_intr.h
index d86bdd3b19bf..2221e28eaaec 100644
--- a/drivers/video/tegra/host/nvhost_intr.h
+++ b/drivers/video/tegra/host/nvhost_intr.h
@@ -65,6 +65,7 @@ struct nvhost_intr_syncpt {
struct list_head wait_head;
char thresh_irq_name[12];
struct work_struct work;
+ struct timespec isr_recv;
};
struct nvhost_intr {
@@ -116,6 +117,7 @@ int nvhost_intr_init(struct nvhost_intr *intr, u32 irq_gen, u32 irq_sync);
void nvhost_intr_deinit(struct nvhost_intr *intr);
void nvhost_intr_start(struct nvhost_intr *intr, u32 hz);
void nvhost_intr_stop(struct nvhost_intr *intr);
+int nvhost_intr_release_time(void *ref, struct timespec *ts);
irqreturn_t nvhost_syncpt_thresh_fn(void *dev_id);
irqreturn_t nvhost_intr_irq_fn(int irq, void *dev_id);
diff --git a/drivers/video/tegra/host/nvhost_syncpt.c b/drivers/video/tegra/host/nvhost_syncpt.c
index b3eaca305c65..878cea801fc3 100644
--- a/drivers/video/tegra/host/nvhost_syncpt.c
+++ b/drivers/video/tegra/host/nvhost_syncpt.c
@@ -185,7 +185,8 @@ static bool syncpt_update_min_is_expired(
* Main entrypoint for syncpoint value waits.
*/
int nvhost_syncpt_wait_timeout(struct nvhost_syncpt *sp, u32 id,
- u32 thresh, u32 timeout, u32 *value)
+ u32 thresh, u32 timeout, u32 *value,
+ struct timespec *ts)
{
DECLARE_WAIT_QUEUE_HEAD_ONSTACK(wq);
void *ref;
@@ -200,6 +201,8 @@ int nvhost_syncpt_wait_timeout(struct nvhost_syncpt *sp, u32 id,
if (nvhost_syncpt_is_expired(sp, id, thresh)) {
if (value)
*value = nvhost_syncpt_read_min(sp, id);
+ if (ts)
+ ktime_get_ts(ts);
return 0;
}
@@ -211,6 +214,8 @@ int nvhost_syncpt_wait_timeout(struct nvhost_syncpt *sp, u32 id,
if (nvhost_syncpt_is_expired(sp, id, thresh)) {
if (value)
*value = val;
+ if (ts)
+ ktime_get_ts(ts);
goto done;
}
@@ -247,6 +252,12 @@ int nvhost_syncpt_wait_timeout(struct nvhost_syncpt *sp, u32 id,
if (remain > 0 || nvhost_syncpt_is_expired(sp, id, thresh)) {
if (value)
*value = nvhost_syncpt_read_min(sp, id);
+ if (ts) {
+ err = nvhost_intr_release_time(ref, ts);
+ if (err)
+ ktime_get_ts(ts);
+ }
+
err = 0;
break;
}
@@ -645,7 +656,7 @@ u32 nvhost_syncpt_read_ext(struct platform_device *dev, u32 id)
}
int nvhost_syncpt_wait_timeout_ext(struct platform_device *dev, u32 id,
- u32 thresh, u32 timeout, u32 *value)
+ u32 thresh, u32 timeout, u32 *value, struct timespec *ts)
{
struct platform_device *pdev;
struct nvhost_syncpt *sp;
@@ -659,5 +670,5 @@ int nvhost_syncpt_wait_timeout_ext(struct platform_device *dev, u32 id,
pdev = to_platform_device(dev->dev.parent);
sp = &(nvhost_get_host(pdev)->syncpt);
- return nvhost_syncpt_wait_timeout(sp, id, thresh, timeout, value);
+ return nvhost_syncpt_wait_timeout(sp, id, thresh, timeout, value, ts);
}
diff --git a/drivers/video/tegra/host/nvhost_syncpt.h b/drivers/video/tegra/host/nvhost_syncpt.h
index 10c87865d86a..9fa31d1d03b5 100644
--- a/drivers/video/tegra/host/nvhost_syncpt.h
+++ b/drivers/video/tegra/host/nvhost_syncpt.h
@@ -141,12 +141,12 @@ void nvhost_syncpt_cpu_set_wait_base(struct platform_device *pdev, u32 id,
void nvhost_syncpt_incr(struct nvhost_syncpt *sp, u32 id);
int nvhost_syncpt_wait_timeout(struct nvhost_syncpt *sp, u32 id, u32 thresh,
- u32 timeout, u32 *value);
+ u32 timeout, u32 *value, struct timespec *ts);
static inline int nvhost_syncpt_wait(struct nvhost_syncpt *sp, u32 id, u32 thresh)
{
return nvhost_syncpt_wait_timeout(sp, id, thresh,
- MAX_SCHEDULE_TIMEOUT, NULL);
+ MAX_SCHEDULE_TIMEOUT, NULL, NULL);
}
int nvhost_syncpt_patch_wait(struct nvhost_syncpt *sp, void *patch_addr);