diff options
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/video/tegra/host/host1x/host1x_channel.c | 4 | ||||
-rw-r--r-- | drivers/video/tegra/host/nvhost_cdma.c | 2 | ||||
-rw-r--r-- | drivers/video/tegra/host/nvhost_syncpt.c | 81 | ||||
-rw-r--r-- | drivers/video/tegra/host/nvhost_syncpt.h | 13 |
4 files changed, 75 insertions, 25 deletions
diff --git a/drivers/video/tegra/host/host1x/host1x_channel.c b/drivers/video/tegra/host/host1x/host1x_channel.c index 34ae8879ba18..7fac426107e7 100644 --- a/drivers/video/tegra/host/host1x/host1x_channel.c +++ b/drivers/video/tegra/host/host1x/host1x_channel.c @@ -424,7 +424,7 @@ int host1x_channel_read_3d_reg( read_waiter = NULL; WARN(err, "Failed to set wakeup interrupt"); wait_event(wq, - nvhost_syncpt_min_cmp(&nvhost_get_host(channel->dev)->syncpt, + nvhost_syncpt_is_expired(&nvhost_get_host(channel->dev)->syncpt, p->syncpt, syncval - 2)); nvhost_intr_put_ref(&nvhost_get_host(channel->dev)->intr, ref); @@ -573,7 +573,7 @@ int host1x_save_context(struct nvhost_device *dev, u32 syncpt_id) wakeup_waiter = NULL; WARN(err, "Failed to set wakeup interrupt"); wait_event(wq, - nvhost_syncpt_min_cmp(&nvhost_get_host(ch->dev)->syncpt, + nvhost_syncpt_is_expired(&nvhost_get_host(ch->dev)->syncpt, syncpt_id, syncpt_val)); nvhost_intr_put_ref(&nvhost_get_host(ch->dev)->intr, ref); diff --git a/drivers/video/tegra/host/nvhost_cdma.c b/drivers/video/tegra/host/nvhost_cdma.c index 390497759020..775d761e65c9 100644 --- a/drivers/video/tegra/host/nvhost_cdma.c +++ b/drivers/video/tegra/host/nvhost_cdma.c @@ -163,7 +163,7 @@ static void update_cdma_locked(struct nvhost_cdma *cdma) BUG_ON(job->syncpt_id == NVSYNCPT_INVALID); /* Check whether this syncpt has completed, and bail if not */ - if (!nvhost_syncpt_min_cmp(sp, + if (!nvhost_syncpt_is_expired(sp, job->syncpt_id, job->syncpt_end)) { /* Start timer on next pending syncpt */ if (job->timeout) diff --git a/drivers/video/tegra/host/nvhost_syncpt.c b/drivers/video/tegra/host/nvhost_syncpt.c index 4e2bec77da65..c41ecd99d909 100644 --- a/drivers/video/tegra/host/nvhost_syncpt.c +++ b/drivers/video/tegra/host/nvhost_syncpt.c @@ -143,7 +143,7 @@ int nvhost_syncpt_wait_timeout(struct nvhost_syncpt *sp, u32 id, } /* first check cache */ - if (nvhost_syncpt_min_cmp(sp, id, thresh)) { + if (nvhost_syncpt_is_expired(sp, id, thresh)) { if (value) *value = nvhost_syncpt_read_min(sp, id); return 0; @@ -182,13 +182,17 @@ int nvhost_syncpt_wait_timeout(struct nvhost_syncpt *sp, u32 id, goto done; err = -EAGAIN; + /* Caller-specified timeout may be impractically low */ + if (timeout < SYNCPT_CHECK_PERIOD) + low_timeout = timeout; + /* wait for the syncpoint, or timeout, or signal */ while (timeout) { u32 check = min_t(u32, SYNCPT_CHECK_PERIOD, timeout); int remain = wait_event_interruptible_timeout(wq, - nvhost_syncpt_min_cmp(sp, id, thresh), - check); - if (remain > 0 || nvhost_syncpt_min_cmp(sp, id, thresh)) { + nvhost_syncpt_is_expired(sp, id, thresh), + check); + if (remain > 0 || nvhost_syncpt_is_expired(sp, id, thresh)) { if (value) *value = nvhost_syncpt_read_min(sp, id); err = 0; @@ -198,13 +202,8 @@ int nvhost_syncpt_wait_timeout(struct nvhost_syncpt *sp, u32 id, err = remain; break; } - if (timeout != NVHOST_NO_TIMEOUT) { - if (timeout < SYNCPT_CHECK_PERIOD) { - /* Caller-specified timeout may be impractically low */ - low_timeout = timeout; - } + if (timeout != NVHOST_NO_TIMEOUT) timeout -= check; - } if (timeout) { dev_warn(&syncpt_to_dev(sp)->dev->dev, "%s: syncpoint id %d (%s) stuck waiting %d, timeout=%d\n", @@ -230,6 +229,68 @@ done: return err; } +/** + * Returns true if syncpoint is expired, false if we may need to wait + */ +bool nvhost_syncpt_is_expired( + struct nvhost_syncpt *sp, + u32 id, + u32 thresh) +{ + u32 current_val; + u32 future_val; + smp_rmb(); + current_val = (u32)atomic_read(&sp->min_val[id]); + future_val = (u32)atomic_read(&sp->max_val[id]); + + /* Note the use of unsigned arithmetic here (mod 1<<32). + * + * c = current_val = min_val = the current value of the syncpoint. + * t = thresh = the value we are checking + * f = future_val = max_val = the value c will reach when all + * outstanding increments have completed. + * + * Note that c always chases f until it reaches f. + * + * Dtf = (f - t) + * Dtc = (c - t) + * + * Consider all cases: + * + * A) .....c..t..f..... Dtf < Dtc need to wait + * B) .....c.....f..t.. Dtf > Dtc expired + * C) ..t..c.....f..... Dtf > Dtc expired (Dct very large) + * + * Any case where f==c: always expired (for any t). Dtf == Dcf + * Any case where t==c: always expired (for any f). Dtf >= Dtc (because Dtc==0) + * Any case where t==f!=c: always wait. Dtf < Dtc (because Dtf==0, + * Dtc!=0) + * + * Other cases: + * + * A) .....t..f..c..... Dtf < Dtc need to wait + * A) .....f..c..t..... Dtf < Dtc need to wait + * A) .....f..t..c..... Dtf > Dtc expired + * + * So: + * Dtf >= Dtc implies EXPIRED (return true) + * Dtf < Dtc implies WAIT (return false) + * + * Note: If t is expired then we *cannot* wait on it. We would wait + * forever (hang the system). + * + * Note: do NOT get clever and remove the -thresh from both sides. It + * is NOT the same. + * + * If future valueis zero, we have a client managed sync point. In that + * case we do a direct comparison. + */ + if (!client_managed(id)) + return future_val - thresh >= current_val - thresh; + else + return (s32)(current_val - thresh) >= 0; +} + void nvhost_syncpt_debug(struct nvhost_syncpt *sp) { syncpt_op(sp).debug(sp); diff --git a/drivers/video/tegra/host/nvhost_syncpt.h b/drivers/video/tegra/host/nvhost_syncpt.h index 595d95e29240..5b339178d1e1 100644 --- a/drivers/video/tegra/host/nvhost_syncpt.h +++ b/drivers/video/tegra/host/nvhost_syncpt.h @@ -95,18 +95,6 @@ static inline bool nvhost_syncpt_check_max(struct nvhost_syncpt *sp, } /** - * Returns true if syncpoint has reached threshold - */ -static inline bool nvhost_syncpt_min_cmp(struct nvhost_syncpt *sp, - u32 id, u32 thresh) -{ - u32 cur; - smp_rmb(); - cur = (u32)atomic_read(&sp->min_val[id]); - return ((s32)(cur - thresh) >= 0); -} - -/** * Returns true if syncpoint min == max */ static inline bool nvhost_syncpt_min_eq_max(struct nvhost_syncpt *sp, u32 id) @@ -121,6 +109,7 @@ static inline bool nvhost_syncpt_min_eq_max(struct nvhost_syncpt *sp, u32 id) void nvhost_syncpt_cpu_incr(struct nvhost_syncpt *sp, u32 id); u32 nvhost_syncpt_update_min(struct nvhost_syncpt *sp, u32 id); +bool nvhost_syncpt_is_expired(struct nvhost_syncpt *sp, u32 id, u32 thresh); void nvhost_syncpt_save(struct nvhost_syncpt *sp); |