diff options
author | Andy Walls <awalls@radix.net> | 2008-12-08 21:02:45 -0500 |
---|---|---|
committer | Mauro Carvalho Chehab <mchehab@redhat.com> | 2008-12-30 06:38:29 -0500 |
commit | 66c2a6b0bc0b394d215768610d96f44cf97052ac (patch) | |
tree | a88946e764eb5a829a920c5027b4d92922cc54ee /drivers/media/video/cx18/cx18-queue.c | |
parent | b80e1074c734416987486b7b76b6479faa73f1e2 (diff) |
V4L/DVB (9801): cx18: Allow more than 63 capture buffers in rotation per stream
cx18: Allow more than 63 capture buffers in rotation per stream. Implement
q_busy to hold buffers the firmware has for use. q_free holds truly unused
buffers in a pool. New buffers are given to the firmware as soon as the
firmware returns one, if there are any to give to the firmware.
Signed-off-by: Andy Walls <awalls@radix.net>
Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
Diffstat (limited to 'drivers/media/video/cx18/cx18-queue.c')
-rw-r--r-- | drivers/media/video/cx18/cx18-queue.c | 56 |
1 files changed, 29 insertions, 27 deletions
diff --git a/drivers/media/video/cx18/cx18-queue.c b/drivers/media/video/cx18/cx18-queue.c index fdfc83ee3d4e..40379d807cef 100644 --- a/drivers/media/video/cx18/cx18-queue.c +++ b/drivers/media/video/cx18/cx18-queue.c | |||
@@ -42,24 +42,32 @@ void cx18_queue_init(struct cx18_queue *q) | |||
42 | q->bytesused = 0; | 42 | q->bytesused = 0; |
43 | } | 43 | } |
44 | 44 | ||
45 | void _cx18_enqueue(struct cx18_stream *s, struct cx18_buffer *buf, | 45 | struct cx18_queue *_cx18_enqueue(struct cx18_stream *s, struct cx18_buffer *buf, |
46 | struct cx18_queue *q, int to_front) | 46 | struct cx18_queue *q, int to_front) |
47 | { | 47 | { |
48 | /* clear the buffer if it is going to be enqueued to the free queue */ | 48 | /* clear the buffer if it is not to be enqueued to the full queue */ |
49 | if (q == &s->q_free) { | 49 | if (q != &s->q_full) { |
50 | buf->bytesused = 0; | 50 | buf->bytesused = 0; |
51 | buf->readpos = 0; | 51 | buf->readpos = 0; |
52 | buf->b_flags = 0; | 52 | buf->b_flags = 0; |
53 | buf->skipped = 0; | 53 | buf->skipped = 0; |
54 | } | 54 | } |
55 | |||
55 | mutex_lock(&s->qlock); | 56 | mutex_lock(&s->qlock); |
57 | |||
58 | /* q_busy is restricted to 63 buffers to stay within firmware limits */ | ||
59 | if (q == &s->q_busy && atomic_read(&q->buffers) >= 63) | ||
60 | q = &s->q_free; | ||
61 | |||
56 | if (to_front) | 62 | if (to_front) |
57 | list_add(&buf->list, &q->list); /* LIFO */ | 63 | list_add(&buf->list, &q->list); /* LIFO */ |
58 | else | 64 | else |
59 | list_add_tail(&buf->list, &q->list); /* FIFO */ | 65 | list_add_tail(&buf->list, &q->list); /* FIFO */ |
60 | atomic_inc(&q->buffers); | ||
61 | q->bytesused += buf->bytesused - buf->readpos; | 66 | q->bytesused += buf->bytesused - buf->readpos; |
67 | atomic_inc(&q->buffers); | ||
68 | |||
62 | mutex_unlock(&s->qlock); | 69 | mutex_unlock(&s->qlock); |
70 | return q; | ||
63 | } | 71 | } |
64 | 72 | ||
65 | struct cx18_buffer *cx18_dequeue(struct cx18_stream *s, struct cx18_queue *q) | 73 | struct cx18_buffer *cx18_dequeue(struct cx18_stream *s, struct cx18_queue *q) |
@@ -70,9 +78,9 @@ struct cx18_buffer *cx18_dequeue(struct cx18_stream *s, struct cx18_queue *q) | |||
70 | if (!list_empty(&q->list)) { | 78 | if (!list_empty(&q->list)) { |
71 | buf = list_entry(q->list.next, struct cx18_buffer, list); | 79 | buf = list_entry(q->list.next, struct cx18_buffer, list); |
72 | list_del_init(q->list.next); | 80 | list_del_init(q->list.next); |
73 | atomic_dec(&q->buffers); | ||
74 | q->bytesused -= buf->bytesused - buf->readpos; | 81 | q->bytesused -= buf->bytesused - buf->readpos; |
75 | buf->skipped = 0; | 82 | buf->skipped = 0; |
83 | atomic_dec(&q->buffers); | ||
76 | } | 84 | } |
77 | mutex_unlock(&s->qlock); | 85 | mutex_unlock(&s->qlock); |
78 | return buf; | 86 | return buf; |
@@ -85,28 +93,30 @@ struct cx18_buffer *cx18_queue_get_buf(struct cx18_stream *s, u32 id, | |||
85 | struct cx18_buffer *buf; | 93 | struct cx18_buffer *buf; |
86 | struct cx18_buffer *ret = NULL; | 94 | struct cx18_buffer *ret = NULL; |
87 | struct list_head *p, *t; | 95 | struct list_head *p, *t; |
88 | LIST_HEAD(r); | ||
89 | 96 | ||
90 | mutex_lock(&s->qlock); | 97 | mutex_lock(&s->qlock); |
91 | list_for_each_safe(p, t, &s->q_free.list) { | 98 | list_for_each_safe(p, t, &s->q_busy.list) { |
92 | buf = list_entry(p, struct cx18_buffer, list); | 99 | buf = list_entry(p, struct cx18_buffer, list); |
93 | 100 | ||
94 | if (buf->id != id) { | 101 | if (buf->id != id) { |
95 | buf->skipped++; | 102 | buf->skipped++; |
96 | if (buf->skipped >= atomic_read(&s->q_free.buffers)-1) { | 103 | if (buf->skipped >= atomic_read(&s->q_busy.buffers)-1) { |
97 | /* buffer must have fallen out of rotation */ | 104 | /* buffer must have fallen out of rotation */ |
98 | atomic_dec(&s->q_free.buffers); | ||
99 | list_move_tail(&buf->list, &r); | ||
100 | CX18_WARN("Skipped %s, buffer %d, %d " | 105 | CX18_WARN("Skipped %s, buffer %d, %d " |
101 | "times - it must have dropped out of " | 106 | "times - it must have dropped out of " |
102 | "rotation\n", s->name, buf->id, | 107 | "rotation\n", s->name, buf->id, |
103 | buf->skipped); | 108 | buf->skipped); |
109 | /* move it to q_free */ | ||
110 | list_move_tail(&buf->list, &s->q_free.list); | ||
111 | buf->bytesused = buf->readpos = buf->b_flags = | ||
112 | buf->skipped = 0; | ||
113 | atomic_dec(&s->q_busy.buffers); | ||
114 | atomic_inc(&s->q_free.buffers); | ||
104 | } | 115 | } |
105 | continue; | 116 | continue; |
106 | } | 117 | } |
107 | 118 | ||
108 | buf->bytesused = bytesused; | 119 | buf->bytesused = bytesused; |
109 | atomic_dec(&s->q_free.buffers); | ||
110 | if (s->type == CX18_ENC_STREAM_TYPE_TS) { | 120 | if (s->type == CX18_ENC_STREAM_TYPE_TS) { |
111 | /* | 121 | /* |
112 | * TS doesn't use q_full, but for sweeping up lost | 122 | * TS doesn't use q_full, but for sweeping up lost |
@@ -116,28 +126,19 @@ struct cx18_buffer *cx18_queue_get_buf(struct cx18_stream *s, u32 id, | |||
116 | */ | 126 | */ |
117 | list_del_init(&buf->list); | 127 | list_del_init(&buf->list); |
118 | } else { | 128 | } else { |
119 | atomic_inc(&s->q_full.buffers); | ||
120 | s->q_full.bytesused += buf->bytesused; | ||
121 | list_move_tail(&buf->list, &s->q_full.list); | 129 | list_move_tail(&buf->list, &s->q_full.list); |
130 | s->q_full.bytesused += buf->bytesused; | ||
131 | atomic_inc(&s->q_full.buffers); | ||
122 | } | 132 | } |
133 | atomic_dec(&s->q_busy.buffers); | ||
123 | 134 | ||
124 | ret = buf; | 135 | ret = buf; |
125 | break; | 136 | break; |
126 | } | 137 | } |
127 | mutex_unlock(&s->qlock); | ||
128 | 138 | ||
129 | /* Put lost buffers back into firmware transfer rotation */ | 139 | /* Put more buffers into the transfer rotation from q_free, if we can */ |
130 | while (!list_empty(&r)) { | 140 | cx18_stream_load_fw_queue_nolock(s); |
131 | buf = list_entry(r.next, struct cx18_buffer, list); | 141 | mutex_unlock(&s->qlock); |
132 | list_del_init(r.next); | ||
133 | cx18_enqueue(s, buf, &s->q_free); | ||
134 | cx18_vapi(cx, CX18_CPU_DE_SET_MDL, 5, s->handle, | ||
135 | (void __iomem *)&cx->scb->cpu_mdl[buf->id] - cx->enc_mem, | ||
136 | 1, buf->id, s->buf_size); | ||
137 | CX18_INFO("Returning %s, buffer %d back to transfer rotation\n", | ||
138 | s->name, buf->id); | ||
139 | /* and there was much rejoicing... */ | ||
140 | } | ||
141 | return ret; | 142 | return ret; |
142 | } | 143 | } |
143 | 144 | ||
@@ -162,6 +163,7 @@ static void cx18_queue_flush(struct cx18_stream *s, struct cx18_queue *q) | |||
162 | 163 | ||
163 | void cx18_flush_queues(struct cx18_stream *s) | 164 | void cx18_flush_queues(struct cx18_stream *s) |
164 | { | 165 | { |
166 | cx18_queue_flush(s, &s->q_busy); | ||
165 | cx18_queue_flush(s, &s->q_full); | 167 | cx18_queue_flush(s, &s->q_full); |
166 | } | 168 | } |
167 | 169 | ||