diff options
author | Terje Bergstrom <tbergstrom@nvidia.com> | 2011-10-17 11:27:43 +0300 |
---|---|---|
committer | Dan Willemsen <dwillemsen@nvidia.com> | 2011-11-30 21:49:41 -0800 |
commit | 53f705e6fa59f1feee73fbb489ae180dda337562 (patch) | |
tree | c42f866d987cae55593dda54888a4f4996a92af2 /drivers/video/tegra/host/nvhost_cdma.c | |
parent | 4d8c37b3d77830ac223dde3d6f644f2415ca70a6 (diff) |
video: tegra: host: Add timeout to low-pri throttle
Add timeout to throttling low-priority thread. Low priority threads are
allowed to push work either when push buffer is empty, or when they've
waited for a pre-defined period. Setting the period to 50ms for now.
Bug 864407
Reviewed-on: http://git-master/r/58330
(cherry picked from commit a9469db8c4c04fa7cd8f080bafdca26d99a3018c)
Change-Id: I5fa310acf6cf5563eda6b7343ad82679f76162af
Reviewed-on: http://git-master/r/61734
Reviewed-by: Terje Bergstrom <tbergstrom@nvidia.com>
Tested-by: Terje Bergstrom <tbergstrom@nvidia.com>
Reviewed-by: Yu-Huan Hsu <yhsu@nvidia.com>
Rebase-Id: R587f052c75a23b1a5a2349d4bf0feecc49cad898
Diffstat (limited to 'drivers/video/tegra/host/nvhost_cdma.c')
-rw-r--r-- | drivers/video/tegra/host/nvhost_cdma.c | 66 |
1 files changed, 44 insertions, 22 deletions
diff --git a/drivers/video/tegra/host/nvhost_cdma.c b/drivers/video/tegra/host/nvhost_cdma.c index 769dba7c8b99..551230624eb9 100644 --- a/drivers/video/tegra/host/nvhost_cdma.c +++ b/drivers/video/tegra/host/nvhost_cdma.c @@ -267,7 +267,8 @@ dequeue_sync_queue_head(struct sync_queue *queue) * - pb space: returns the number of free slots in the channel's push buffer * Must be called with the cdma lock held. */ -static unsigned int cdma_status(struct nvhost_cdma *cdma, enum cdma_event event) +static unsigned int cdma_status_locked(struct nvhost_cdma *cdma, + enum cdma_event event) { switch (event) { case CDMA_EVENT_SYNC_QUEUE_EMPTY: @@ -293,10 +294,11 @@ static unsigned int cdma_status(struct nvhost_cdma *cdma, enum cdma_event event) * - Return the amount of space (> 0) * Must be called with the cdma lock held. */ -unsigned int nvhost_cdma_wait(struct nvhost_cdma *cdma, enum cdma_event event) +unsigned int nvhost_cdma_wait_locked(struct nvhost_cdma *cdma, + enum cdma_event event) { for (;;) { - unsigned int space = cdma_status(cdma, event); + unsigned int space = cdma_status_locked(cdma, event); if (space) return space; @@ -317,7 +319,7 @@ unsigned int nvhost_cdma_wait(struct nvhost_cdma *cdma, enum cdma_event event) * Start timer for a buffer submition that has completed yet. * Must be called with the cdma lock held. */ -void nvhost_cdma_start_timer(struct nvhost_cdma *cdma, u32 syncpt_id, +static void cdma_start_timer_locked(struct nvhost_cdma *cdma, u32 syncpt_id, u32 syncpt_val, struct nvhost_userctx_timeout *timeout) { @@ -340,7 +342,7 @@ void nvhost_cdma_start_timer(struct nvhost_cdma *cdma, u32 syncpt_id, * Stop timer when a buffer submition completes. * Must be called with the cdma lock held. */ -static void stop_cdma_timer(struct nvhost_cdma *cdma) +static void stop_cdma_timer_locked(struct nvhost_cdma *cdma) { cancel_delayed_work(&cdma->timeout.wq); cdma->timeout.ctx_timeout = NULL; @@ -356,7 +358,7 @@ static void stop_cdma_timer(struct nvhost_cdma *cdma) * called manually if necessary. * Must be called with the cdma lock held. */ -static void update_cdma(struct nvhost_cdma *cdma) +static void update_cdma_locked(struct nvhost_cdma *cdma) { bool signal = false; struct nvhost_master *dev = cdma_to_dev(cdma); @@ -396,7 +398,7 @@ static void update_cdma(struct nvhost_cdma *cdma) if (!nvhost_syncpt_min_cmp(sp, syncpt_id, syncpt_val)) { /* Start timer on next pending syncpt */ if (timeout) { - nvhost_cdma_start_timer(cdma, syncpt_id, + cdma_start_timer_locked(cdma, syncpt_id, syncpt_val, timeout_ref); } break; @@ -404,7 +406,7 @@ static void update_cdma(struct nvhost_cdma *cdma) /* Cancel timeout, when a buffer completes */ if (cdma->timeout.ctx_timeout) - stop_cdma_timer(cdma); + stop_cdma_timer_locked(cdma); nr_slots = sync[SQ_IDX_NUM_SLOTS]; nr_handles = sync[SQ_IDX_NUM_HANDLES]; @@ -713,7 +715,7 @@ void nvhost_cdma_push_gather(struct nvhost_cdma *cdma, BUG_ON(!cdma_op(cdma).kick); if (slots_free == 0) { cdma_op(cdma).kick(cdma); - slots_free = nvhost_cdma_wait(cdma, + slots_free = nvhost_cdma_wait_locked(cdma, CDMA_EVENT_PUSH_BUFFER_SPACE); } cdma->slots_free = slots_free - 1; @@ -746,7 +748,8 @@ void nvhost_cdma_end(struct nvhost_cdma *cdma, * Wait until there's enough room in the * sync queue to write something. */ - count = nvhost_cdma_wait(cdma, CDMA_EVENT_SYNC_QUEUE_SPACE); + count = nvhost_cdma_wait_locked(cdma, + CDMA_EVENT_SYNC_QUEUE_SPACE); /* Add reloc entries to sync queue (as many as will fit) */ if (count > nr_handles) @@ -765,7 +768,7 @@ void nvhost_cdma_end(struct nvhost_cdma *cdma, /* start timer on idle -> active transitions */ if (timeout->timeout && was_idle) { - nvhost_cdma_start_timer(cdma, sync_point_id, sync_point_value, + cdma_start_timer_locked(cdma, sync_point_id, sync_point_value, timeout); } @@ -778,23 +781,42 @@ void nvhost_cdma_end(struct nvhost_cdma *cdma, void nvhost_cdma_update(struct nvhost_cdma *cdma) { mutex_lock(&cdma->lock); - update_cdma(cdma); + update_cdma_locked(cdma); mutex_unlock(&cdma->lock); } /** - * Manually spin until all CDMA has finished. Used if an async update - * cannot be scheduled for any reason. + * Wait for push buffer to be empty. + * @cdma pointer to channel cdma + * @timeout timeout in ms + * Returns -ETIME if timeout was reached, zero if push buffer is empty. */ -void nvhost_cdma_flush(struct nvhost_cdma *cdma) +int nvhost_cdma_flush(struct nvhost_cdma *cdma, int timeout) { - mutex_lock(&cdma->lock); - while (sync_queue_head(&cdma->sync_queue)) { - update_cdma(cdma); - mutex_unlock(&cdma->lock); - schedule(); + unsigned int space, err = 0; + unsigned long end_jiffies = jiffies + msecs_to_jiffies(timeout); + + /* + * Wait for at most timeout ms. Recalculate timeout at each iteration + * to better keep within given timeout. + */ + while(!err && time_before(jiffies, end_jiffies)) { + int timeout_jiffies = end_jiffies - jiffies; + mutex_lock(&cdma->lock); + space = cdma_status_locked(cdma, + CDMA_EVENT_SYNC_QUEUE_EMPTY); + if (space) { + mutex_unlock(&cdma->lock); + return 0; + } + + BUG_ON(cdma->event != CDMA_EVENT_NONE); + cdma->event = CDMA_EVENT_SYNC_QUEUE_EMPTY; + + mutex_unlock(&cdma->lock); + err = down_timeout(&cdma->sem, + jiffies_to_msecs(timeout_jiffies)); } - mutex_unlock(&cdma->lock); + return err; } - |