diff options
author | Arto Merilainen <amerilainen@nvidia.com> | 2012-09-26 16:05:18 +0300 |
---|---|---|
committer | Dan Willemsen <dwillemsen@nvidia.com> | 2013-09-14 13:04:11 -0700 |
commit | 8e2a4e9c836c56652965d6950b830809f0eda89f (patch) | |
tree | 96f771d3a75aeea76070e04f17d861031de2acf5 /drivers/video | |
parent | bb0b53207c647152d278895e909d19da30267411 (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.c | 2 | ||||
-rw-r--r-- | drivers/video/tegra/dc/ext/dev.c | 2 | ||||
-rw-r--r-- | drivers/video/tegra/host/host1x/host1x.c | 30 | ||||
-rw-r--r-- | drivers/video/tegra/host/host1x/host1x_intr.c | 2 | ||||
-rw-r--r-- | drivers/video/tegra/host/nvhost_intr.c | 16 | ||||
-rw-r--r-- | drivers/video/tegra/host/nvhost_intr.h | 2 | ||||
-rw-r--r-- | drivers/video/tegra/host/nvhost_syncpt.c | 17 | ||||
-rw-r--r-- | drivers/video/tegra/host/nvhost_syncpt.h | 4 |
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, ®, 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); |