diff options
author | Terje Bergstrom <tbergstrom@nvidia.com> | 2012-01-30 13:37:07 +0200 |
---|---|---|
committer | Lokesh Pathak <lpathak@nvidia.com> | 2012-02-22 22:15:41 -0800 |
commit | 304ea342746da8db6926bb5a84e9d570c7462107 (patch) | |
tree | 4f1cddbad6a7be2c1ccfacf1cbabf262a8ad5970 | |
parent | 73dd1497bd101d10a3dd980915a8d3899d8ba5c4 (diff) |
video: tegra: host: Change sync queue to a list
Sync queue is the list of jobs still in flight. As context priorities
requires possibility to insert a job in the middle of the queue, the
structure needs to be changed into a linked list.
Bug 926690
Change-Id: Id257a11f18476c70dd69e36ba44ed2d380c80040
Signed-off-by: Terje Bergstrom <tbergstrom@nvidia.com>
Reviewed-on: http://git-master/r/83127
-rw-r--r-- | drivers/video/tegra/host/dev.h | 2 | ||||
-rw-r--r-- | drivers/video/tegra/host/host1x/host1x_cdma.c | 2 | ||||
-rw-r--r-- | drivers/video/tegra/host/nvhost_cdma.c | 106 | ||||
-rw-r--r-- | drivers/video/tegra/host/nvhost_cdma.h | 5 | ||||
-rw-r--r-- | drivers/video/tegra/host/nvhost_job.h | 3 |
5 files changed, 30 insertions, 88 deletions
diff --git a/drivers/video/tegra/host/dev.h b/drivers/video/tegra/host/dev.h index 7b6fd99746dc..67d78aabfa6a 100644 --- a/drivers/video/tegra/host/dev.h +++ b/drivers/video/tegra/host/dev.h @@ -47,8 +47,6 @@ struct nvhost_master { struct nvhost_channel *channels; u32 nb_channels; - u32 sync_queue_size; - struct nvhost_chip_support op; atomic_t clientid; diff --git a/drivers/video/tegra/host/host1x/host1x_cdma.c b/drivers/video/tegra/host/host1x/host1x_cdma.c index 65a72801528f..1006fbd90f88 100644 --- a/drivers/video/tegra/host/host1x/host1x_cdma.c +++ b/drivers/video/tegra/host/host1x/host1x_cdma.c @@ -655,8 +655,6 @@ int host1x_init_cdma_support(struct nvhost_master *host) host->op.cdma.timeout_cpu_incr = cdma_timeout_cpu_incr; host->op.cdma.timeout_pb_incr = cdma_timeout_pb_incr; - host->sync_queue_size = NVHOST_SYNC_QUEUE_SIZE; - host->op.push_buffer.reset = push_buffer_reset; host->op.push_buffer.init = push_buffer_init; host->op.push_buffer.destroy = push_buffer_destroy; diff --git a/drivers/video/tegra/host/nvhost_cdma.c b/drivers/video/tegra/host/nvhost_cdma.c index 6446befbdd58..908d8bb1da04 100644 --- a/drivers/video/tegra/host/nvhost_cdma.c +++ b/drivers/video/tegra/host/nvhost_cdma.c @@ -33,36 +33,11 @@ * TODO: * stats * - for figuring out what to optimize further - * resizable push buffer & sync queue + * resizable push buffer * - some channels hardly need any, some channels (3d) could use more */ /** - * kfifo_save - save current out pointer - * @fifo: address of the fifo to be used - */ -#define kfifo_save(fifo) \ -__kfifo_uint_must_check_helper( \ -({ \ - typeof((fifo) + 1) __tmp = (fifo); \ - struct __kfifo *__kfifo = &__tmp->kfifo; \ - __kfifo->out; \ -}) \ -) - -/** - * kfifo_restore - restore previously saved pointer - * @fifo: address of the fifo to be used - * @out: output pointer - */ -#define kfifo_restore(fifo, restore) \ -(void)({ \ - typeof((fifo) + 1) __tmp = (fifo); \ - struct __kfifo *__kfifo = &__tmp->kfifo; \ - __kfifo->out = (restore); \ -}) - -/** * Add an entry to the sync queue. */ static void add_to_sync_queue(struct nvhost_cdma *cdma, @@ -75,13 +50,12 @@ static void add_to_sync_queue(struct nvhost_cdma *cdma, job->first_get = first_get; job->num_slots = nr_slots; nvhost_job_get(job); - kfifo_in(&cdma->sync_queue, (void *)&job, 1); + list_add_tail(&job->list, &cdma->sync_queue); } /** * Return the status of the cdma's sync queue or push buffer for the given event * - sq empty: returns 1 for empty, 0 for not empty (as in "1 empty queue" :-) - * - sq space: returns the number of handles that can be stored in the queue * - pb space: returns the number of free slots in the channel's push buffer * Must be called with the cdma lock held. */ @@ -90,9 +64,7 @@ static unsigned int cdma_status_locked(struct nvhost_cdma *cdma, { switch (event) { case CDMA_EVENT_SYNC_QUEUE_EMPTY: - return kfifo_len(&cdma->sync_queue) == 0 ? 1 : 0; - case CDMA_EVENT_SYNC_QUEUE_SPACE: - return kfifo_avail(&cdma->sync_queue); + return list_empty(&cdma->sync_queue) ? 1 : 0; case CDMA_EVENT_PUSH_BUFFER_SPACE: { struct push_buffer *pb = &cdma->push_buffer; BUG_ON(!cdma_pb_op(cdma).space); @@ -107,7 +79,6 @@ static unsigned int cdma_status_locked(struct nvhost_cdma *cdma, * Sleep (if necessary) until the requested event happens * - CDMA_EVENT_SYNC_QUEUE_EMPTY : sync queue is completely empty. * - Returns 1 - * - CDMA_EVENT_SYNC_QUEUE_SPACE : there is space in the sync queue. * - CDMA_EVENT_PUSH_BUFFER_SPACE : there is space in the push buffer * - Return the amount of space (> 0) * Must be called with the cdma lock held. @@ -181,6 +152,8 @@ static void update_cdma_locked(struct nvhost_cdma *cdma) { bool signal = false; struct nvhost_master *dev = cdma_to_dev(cdma); + struct nvhost_syncpt *sp = &dev->syncpt; + struct nvhost_job *job, *n; BUG_ON(!cdma->running); @@ -188,18 +161,7 @@ static void update_cdma_locked(struct nvhost_cdma *cdma) * Walk the sync queue, reading the sync point registers as necessary, * to consume as many sync queue entries as possible without blocking */ - for (;;) { - struct nvhost_syncpt *sp = &dev->syncpt; - struct nvhost_job *job; - int result; - - result = kfifo_peek(&cdma->sync_queue, &job); - if (!result) { - if (cdma->event == CDMA_EVENT_SYNC_QUEUE_EMPTY) - signal = true; - break; - } - + list_for_each_entry_safe(job, n, &cdma->sync_queue, list) { BUG_ON(job->syncpt_id == NVSYNCPT_INVALID); /* Check whether this syncpt has completed, and bail if not */ @@ -227,12 +189,14 @@ static void update_cdma_locked(struct nvhost_cdma *cdma) signal = true; } + list_del(&job->list); nvhost_job_put(job); - kfifo_skip(&cdma->sync_queue); - if (cdma->event == CDMA_EVENT_SYNC_QUEUE_SPACE) - signal = true; } + if (list_empty(&cdma->sync_queue) && + cdma->event == CDMA_EVENT_SYNC_QUEUE_EMPTY) + signal = true; + /* Wake up CdmaWait() if the requested event happened */ if (signal) { cdma->event = CDMA_EVENT_NONE; @@ -246,18 +210,14 @@ void nvhost_cdma_update_sync_queue(struct nvhost_cdma *cdma, u32 get_restart; u32 syncpt_incrs; bool exec_ctxsave; - unsigned int queue_restore; struct nvhost_job *job = NULL; - int result; u32 syncpt_val; syncpt_val = nvhost_syncpt_update_min(syncpt, cdma->timeout.syncpt_id); - queue_restore = kfifo_save(&cdma->sync_queue); dev_dbg(dev, - "%s: starting cleanup (thresh %d, queue length %d)\n", - __func__, - syncpt_val, kfifo_len(&cdma->sync_queue)); + "%s: starting cleanup (thresh %d)\n", + __func__, syncpt_val); /* * Move the sync_queue read pointer to the first entry that hasn't @@ -270,11 +230,11 @@ void nvhost_cdma_update_sync_queue(struct nvhost_cdma *cdma, "%s: skip completed buffers still in sync_queue\n", __func__); - result = kfifo_peek(&cdma->sync_queue, &job); - while (result && syncpt_val >= job->syncpt_end) { + list_for_each_entry(job, &cdma->sync_queue, list) { + if (syncpt_val < job->syncpt_end) + break; + nvhost_job_dump(dev, job); - kfifo_skip(&cdma->sync_queue); - result = kfifo_peek(&cdma->sync_queue, &job); } /* @@ -297,11 +257,11 @@ void nvhost_cdma_update_sync_queue(struct nvhost_cdma *cdma, __func__); get_restart = cdma->last_put; - if (kfifo_len(&cdma->sync_queue) > 0) + if (!list_empty(&cdma->sync_queue)) get_restart = job->first_get; /* do CPU increments as long as this context continues */ - while (result && job->clientid == cdma->timeout.clientid) { + list_for_each_entry_from(job, &cdma->sync_queue, list) { /* different context, gets us out of this loop */ if (job->clientid != cdma->timeout.clientid) break; @@ -323,8 +283,6 @@ void nvhost_cdma_update_sync_queue(struct nvhost_cdma *cdma, job->num_slots); syncpt_val += syncpt_incrs; - kfifo_skip(&cdma->sync_queue); - result = kfifo_peek(&cdma->sync_queue, &job); } dev_dbg(dev, @@ -334,7 +292,7 @@ void nvhost_cdma_update_sync_queue(struct nvhost_cdma *cdma, exec_ctxsave = false; /* setup GPU increments */ - while (result) { + list_for_each_entry_from(job, &cdma->sync_queue, list) { /* same context, increment in the pushbuffer */ if (job->clientid == cdma->timeout.clientid) { /* won't need a timeout when replayed */ @@ -360,16 +318,11 @@ void nvhost_cdma_update_sync_queue(struct nvhost_cdma *cdma, } nvhost_job_dump(dev, job); - - kfifo_skip(&cdma->sync_queue); - result = kfifo_peek(&cdma->sync_queue, &job); } dev_dbg(dev, "%s: finished sync_queue modification\n", __func__); - kfifo_restore(&cdma->sync_queue, queue_restore); - /* roll back DMAGET and start up channel again */ cdma_op(cdma).timeout_teardown_end(cdma, get_restart); @@ -388,12 +341,7 @@ int nvhost_cdma_init(struct nvhost_cdma *cdma) mutex_init(&cdma->lock); sema_init(&cdma->sem, 0); - err = kfifo_alloc(&cdma->sync_queue, - cdma_to_dev(cdma)->sync_queue_size - * sizeof(struct nvhost_job *), - GFP_KERNEL); - if (err) - return err; + INIT_LIST_HEAD(&cdma->sync_queue); cdma->event = CDMA_EVENT_NONE; cdma->running = false; @@ -414,7 +362,6 @@ void nvhost_cdma_deinit(struct nvhost_cdma *cdma) BUG_ON(!cdma_pb_op(cdma).destroy); BUG_ON(cdma->running); - kfifo_free(&cdma->sync_queue); cdma_pb_op(cdma).destroy(pb); cdma_op(cdma).timeout_destroy(cdma); } @@ -482,23 +429,20 @@ void nvhost_cdma_push_gather(struct nvhost_cdma *cdma, /** * End a cdma submit - * Kick off DMA, add a contiguous block of memory handles to the sync queue, - * and a number of slots to be freed from the pushbuffer. - * Blocks as necessary if the sync queue is full. - * The handles for a submit must all be pinned at the same time, but they - * can be unpinned in smaller chunks. + * Kick off DMA, add job to the sync queue, and a number of slots to be freed + * from the pushbuffer. The handles for a submit must all be pinned at the same + * time, but they can be unpinned in smaller chunks. */ void nvhost_cdma_end(struct nvhost_cdma *cdma, struct nvhost_job *job) { - bool was_idle = kfifo_len(&cdma->sync_queue) == 0; + bool was_idle = list_empty(&cdma->sync_queue); BUG_ON(!cdma_op(cdma).kick); cdma_op(cdma).kick(cdma); BUG_ON(job->syncpt_id == NVSYNCPT_INVALID); - nvhost_cdma_wait_locked(cdma, CDMA_EVENT_SYNC_QUEUE_SPACE); add_to_sync_queue(cdma, job, cdma->slots_used, diff --git a/drivers/video/tegra/host/nvhost_cdma.h b/drivers/video/tegra/host/nvhost_cdma.h index a5ef8da29e78..48c8cb2e8a26 100644 --- a/drivers/video/tegra/host/nvhost_cdma.h +++ b/drivers/video/tegra/host/nvhost_cdma.h @@ -28,7 +28,7 @@ #include <linux/nvhost.h> #include <mach/nvmap.h> -#include <linux/kfifo.h> +#include <linux/list.h> #include "nvhost_acm.h" @@ -87,7 +87,6 @@ struct buffer_timeout { enum cdma_event { CDMA_EVENT_NONE, /* not waiting for any event */ CDMA_EVENT_SYNC_QUEUE_EMPTY, /* wait for empty sync queue */ - CDMA_EVENT_SYNC_QUEUE_SPACE, /* wait for space in sync queue */ CDMA_EVENT_PUSH_BUFFER_SPACE /* wait for space in push buffer */ }; @@ -101,7 +100,7 @@ struct nvhost_cdma { unsigned int last_put; /* last value written to DMAPUT */ struct push_buffer push_buffer; /* channel's push buffer */ struct syncpt_buffer syncpt_buffer; /* syncpt incr buffer */ - DECLARE_KFIFO_PTR(sync_queue, struct nvhost_job *); /* job queue */ + struct list_head sync_queue; /* job queue */ struct buffer_timeout timeout; /* channel's timeout state/wq */ bool running; bool torndown; diff --git a/drivers/video/tegra/host/nvhost_job.h b/drivers/video/tegra/host/nvhost_job.h index d00d60f2164a..09b96abb2cfd 100644 --- a/drivers/video/tegra/host/nvhost_job.h +++ b/drivers/video/tegra/host/nvhost_job.h @@ -38,6 +38,9 @@ struct nvhost_job { /* When refcount goes to zero, job can be freed */ struct kref ref; + /* List entry */ + struct list_head list; + /* Channel where job is submitted to */ struct nvhost_channel *ch; |