]> err.no Git - linux-2.6/blob - drivers/media/video/ivtv/ivtv-queue.c
V4L/DVB (6046): ivtv: always steal full frames if out of buffers.
[linux-2.6] / drivers / media / video / ivtv / ivtv-queue.c
1 /*
2     buffer queues.
3     Copyright (C) 2003-2004  Kevin Thayer <nufan_wfk at yahoo.com>
4     Copyright (C) 2004  Chris Kennedy <c@groovy.org>
5     Copyright (C) 2005-2007  Hans Verkuil <hverkuil@xs4all.nl>
6
7     This program is free software; you can redistribute it and/or modify
8     it under the terms of the GNU General Public License as published by
9     the Free Software Foundation; either version 2 of the License, or
10     (at your option) any later version.
11
12     This program is distributed in the hope that it will be useful,
13     but WITHOUT ANY WARRANTY; without even the implied warranty of
14     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15     GNU General Public License for more details.
16
17     You should have received a copy of the GNU General Public License
18     along with this program; if not, write to the Free Software
19     Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
20  */
21
22 #include "ivtv-driver.h"
23 #include "ivtv-streams.h"
24 #include "ivtv-queue.h"
25 #include "ivtv-mailbox.h"
26
27 int ivtv_buf_copy_from_user(struct ivtv_stream *s, struct ivtv_buffer *buf, const char __user *src, int copybytes)
28 {
29         if (s->buf_size - buf->bytesused < copybytes)
30                 copybytes = s->buf_size - buf->bytesused;
31         if (copy_from_user(buf->buf + buf->bytesused, src, copybytes)) {
32                 return -EFAULT;
33         }
34         buf->bytesused += copybytes;
35         return copybytes;
36 }
37
38 void ivtv_buf_swap(struct ivtv_buffer *buf)
39 {
40         int i;
41
42         for (i = 0; i < buf->bytesused; i += 4)
43                 swab32s((u32 *)(buf->buf + i));
44 }
45
46 void ivtv_queue_init(struct ivtv_queue *q)
47 {
48         INIT_LIST_HEAD(&q->list);
49         q->buffers = 0;
50         q->length = 0;
51         q->bytesused = 0;
52 }
53
54 void ivtv_enqueue(struct ivtv_stream *s, struct ivtv_buffer *buf, struct ivtv_queue *q)
55 {
56         unsigned long flags = 0;
57
58         /* clear the buffer if it is going to be enqueued to the free queue */
59         if (q == &s->q_free) {
60                 buf->bytesused = 0;
61                 buf->readpos = 0;
62                 buf->b_flags = 0;
63                 buf->dma_xfer_cnt = 0;
64         }
65         spin_lock_irqsave(&s->qlock, flags);
66         list_add_tail(&buf->list, &q->list);
67         q->buffers++;
68         q->length += s->buf_size;
69         q->bytesused += buf->bytesused - buf->readpos;
70         spin_unlock_irqrestore(&s->qlock, flags);
71 }
72
73 struct ivtv_buffer *ivtv_dequeue(struct ivtv_stream *s, struct ivtv_queue *q)
74 {
75         struct ivtv_buffer *buf = NULL;
76         unsigned long flags = 0;
77
78         spin_lock_irqsave(&s->qlock, flags);
79         if (!list_empty(&q->list)) {
80                 buf = list_entry(q->list.next, struct ivtv_buffer, list);
81                 list_del_init(q->list.next);
82                 q->buffers--;
83                 q->length -= s->buf_size;
84                 q->bytesused -= buf->bytesused - buf->readpos;
85         }
86         spin_unlock_irqrestore(&s->qlock, flags);
87         return buf;
88 }
89
90 static void ivtv_queue_move_buf(struct ivtv_stream *s, struct ivtv_queue *from,
91                 struct ivtv_queue *to, int clear)
92 {
93         struct ivtv_buffer *buf = list_entry(from->list.next, struct ivtv_buffer, list);
94
95         list_move_tail(from->list.next, &to->list);
96         from->buffers--;
97         from->length -= s->buf_size;
98         from->bytesused -= buf->bytesused - buf->readpos;
99         /* special handling for q_free */
100         if (clear)
101                 buf->bytesused = buf->readpos = buf->b_flags = buf->dma_xfer_cnt = 0;
102         to->buffers++;
103         to->length += s->buf_size;
104         to->bytesused += buf->bytesused - buf->readpos;
105 }
106
107 /* Move 'needed_bytes' worth of buffers from queue 'from' into queue 'to'.
108    If 'needed_bytes' == 0, then move all buffers from 'from' into 'to'.
109    If 'steal' != NULL, then buffers may also taken from that queue if
110    needed, but only if 'from' is the free queue.
111
112    The buffer is automatically cleared if it goes to the free queue. It is
113    also cleared if buffers need to be taken from the 'steal' queue and
114    the 'from' queue is the free queue.
115
116    When 'from' is q_free, then needed_bytes is compared to the total
117    available buffer length, otherwise needed_bytes is compared to the
118    bytesused value. For the 'steal' queue the total available buffer
119    length is always used.
120
121    -ENOMEM is returned if the buffers could not be obtained, 0 if all
122    buffers where obtained from the 'from' list and if non-zero then
123    the number of stolen buffers is returned. */
124 int ivtv_queue_move(struct ivtv_stream *s, struct ivtv_queue *from, struct ivtv_queue *steal,
125                     struct ivtv_queue *to, int needed_bytes)
126 {
127         unsigned long flags;
128         int rc = 0;
129         int from_free = from == &s->q_free;
130         int to_free = to == &s->q_free;
131         int bytes_available, bytes_steal;
132
133         spin_lock_irqsave(&s->qlock, flags);
134         if (needed_bytes == 0) {
135                 from_free = 1;
136                 needed_bytes = from->length;
137         }
138
139         bytes_available = from_free ? from->length : from->bytesused;
140         bytes_steal = (from_free && steal) ? steal->length : 0;
141
142         if (bytes_available + bytes_steal < needed_bytes) {
143                 spin_unlock_irqrestore(&s->qlock, flags);
144                 return -ENOMEM;
145         }
146         while (bytes_available < needed_bytes) {
147                 struct ivtv_buffer *buf = list_entry(steal->list.prev, struct ivtv_buffer, list);
148                 u16 dma_xfer_cnt = buf->dma_xfer_cnt;
149
150                 /* move buffers from the tail of the 'steal' queue to the tail of the
151                    'from' queue. Always copy all the buffers with the same dma_xfer_cnt
152                    value, this ensures that you do not end up with partial frame data
153                    if one frame is stored in multiple buffers. */
154                 while (dma_xfer_cnt == buf->dma_xfer_cnt) {
155                         list_move_tail(steal->list.prev, &from->list);
156                         rc++;
157                         steal->buffers--;
158                         steal->length -= s->buf_size;
159                         steal->bytesused -= buf->bytesused - buf->readpos;
160                         buf->bytesused = buf->readpos = buf->b_flags = buf->dma_xfer_cnt = 0;
161                         from->buffers++;
162                         from->length += s->buf_size;
163                         bytes_available += s->buf_size;
164                         if (list_empty(&steal->list))
165                                 break;
166                         buf = list_entry(steal->list.prev, struct ivtv_buffer, list);
167                 }
168         }
169         if (from_free) {
170                 u32 old_length = to->length;
171
172                 while (to->length - old_length < needed_bytes) {
173                         ivtv_queue_move_buf(s, from, to, 1);
174                 }
175         }
176         else {
177                 u32 old_bytesused = to->bytesused;
178
179                 while (to->bytesused - old_bytesused < needed_bytes) {
180                         ivtv_queue_move_buf(s, from, to, to_free);
181                 }
182         }
183         spin_unlock_irqrestore(&s->qlock, flags);
184         return rc;
185 }
186
187 void ivtv_flush_queues(struct ivtv_stream *s)
188 {
189         ivtv_queue_move(s, &s->q_io, NULL, &s->q_free, 0);
190         ivtv_queue_move(s, &s->q_full, NULL, &s->q_free, 0);
191         ivtv_queue_move(s, &s->q_dma, NULL, &s->q_free, 0);
192         ivtv_queue_move(s, &s->q_predma, NULL, &s->q_free, 0);
193 }
194
195 int ivtv_stream_alloc(struct ivtv_stream *s)
196 {
197         struct ivtv *itv = s->itv;
198         int SGsize = sizeof(struct ivtv_SG_element) * s->buffers;
199         int i;
200
201         if (s->buffers == 0)
202                 return 0;
203
204         IVTV_DEBUG_INFO("Allocate %s%s stream: %d x %d buffers (%dkB total)\n",
205                 s->dma != PCI_DMA_NONE ? "DMA " : "",
206                 s->name, s->buffers, s->buf_size, s->buffers * s->buf_size / 1024);
207
208         if (ivtv_might_use_pio(s)) {
209                 s->PIOarray = (struct ivtv_SG_element *)kzalloc(SGsize, GFP_KERNEL);
210                 if (s->PIOarray == NULL) {
211                         IVTV_ERR("Could not allocate PIOarray for %s stream\n", s->name);
212                         return -ENOMEM;
213                 }
214         }
215
216         /* Allocate DMA SG Arrays */
217         s->SGarray = (struct ivtv_SG_element *)kzalloc(SGsize, GFP_KERNEL);
218         if (s->SGarray == NULL) {
219                 IVTV_ERR("Could not allocate SGarray for %s stream\n", s->name);
220                 if (ivtv_might_use_pio(s)) {
221                         kfree(s->PIOarray);
222                         s->PIOarray = NULL;
223                 }
224                 return -ENOMEM;
225         }
226         s->SG_length = 0;
227         if (ivtv_might_use_dma(s)) {
228                 s->SG_handle = pci_map_single(itv->dev, s->SGarray, SGsize, s->dma);
229                 ivtv_stream_sync_for_cpu(s);
230         }
231
232         /* allocate stream buffers. Initially all buffers are in q_free. */
233         for (i = 0; i < s->buffers; i++) {
234                 struct ivtv_buffer *buf = kzalloc(sizeof(struct ivtv_buffer), GFP_KERNEL);
235
236                 if (buf == NULL)
237                         break;
238                 buf->buf = kmalloc(s->buf_size + 256, GFP_KERNEL);
239                 if (buf->buf == NULL) {
240                         kfree(buf);
241                         break;
242                 }
243                 INIT_LIST_HEAD(&buf->list);
244                 if (ivtv_might_use_dma(s)) {
245                         buf->dma_handle = pci_map_single(s->itv->dev,
246                                 buf->buf, s->buf_size + 256, s->dma);
247                         ivtv_buf_sync_for_cpu(s, buf);
248                 }
249                 ivtv_enqueue(s, buf, &s->q_free);
250         }
251         if (i == s->buffers)
252                 return 0;
253         IVTV_ERR("Couldn't allocate buffers for %s stream\n", s->name);
254         ivtv_stream_free(s);
255         return -ENOMEM;
256 }
257
258 void ivtv_stream_free(struct ivtv_stream *s)
259 {
260         struct ivtv_buffer *buf;
261
262         /* move all buffers to q_free */
263         ivtv_flush_queues(s);
264
265         /* empty q_free */
266         while ((buf = ivtv_dequeue(s, &s->q_free))) {
267                 if (ivtv_might_use_dma(s))
268                         pci_unmap_single(s->itv->dev, buf->dma_handle,
269                                 s->buf_size + 256, s->dma);
270                 kfree(buf->buf);
271                 kfree(buf);
272         }
273
274         /* Free SG Array/Lists */
275         if (s->SGarray != NULL) {
276                 if (s->SG_handle != IVTV_DMA_UNMAPPED) {
277                         pci_unmap_single(s->itv->dev, s->SG_handle,
278                                  sizeof(struct ivtv_SG_element) * s->buffers, PCI_DMA_TODEVICE);
279                         s->SG_handle = IVTV_DMA_UNMAPPED;
280                 }
281                 kfree(s->SGarray);
282                 kfree(s->PIOarray);
283                 s->PIOarray = NULL;
284                 s->SGarray = NULL;
285                 s->SG_length = 0;
286         }
287 }