summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTerje Bergstrom <tbergstrom@nvidia.com>2012-01-30 13:37:07 +0200
committerLokesh Pathak <lpathak@nvidia.com>2012-02-22 22:15:41 -0800
commit304ea342746da8db6926bb5a84e9d570c7462107 (patch)
tree4f1cddbad6a7be2c1ccfacf1cbabf262a8ad5970
parent73dd1497bd101d10a3dd980915a8d3899d8ba5c4 (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.h2
-rw-r--r--drivers/video/tegra/host/host1x/host1x_cdma.c2
-rw-r--r--drivers/video/tegra/host/nvhost_cdma.c106
-rw-r--r--drivers/video/tegra/host/nvhost_cdma.h5
-rw-r--r--drivers/video/tegra/host/nvhost_job.h3
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;