V4L/DVB (6047): ivtv: Fix scatter/gather DMA timeouts
[safe/jmp/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         s->sg_pending = (struct ivtv_sg_element *)kzalloc(SGsize, GFP_KERNEL);
209         if (s->sg_pending == NULL) {
210                 IVTV_ERR("Could not allocate sg_pending for %s stream\n", s->name);
211                 return -ENOMEM;
212         }
213         s->sg_pending_size = 0;
214
215         s->sg_processing = (struct ivtv_sg_element *)kzalloc(SGsize, GFP_KERNEL);
216         if (s->sg_processing == NULL) {
217                 IVTV_ERR("Could not allocate sg_processing for %s stream\n", s->name);
218                 kfree(s->sg_pending);
219                 s->sg_pending = NULL;
220                 return -ENOMEM;
221         }
222         s->sg_processing_size = 0;
223
224         s->sg_dma = (struct ivtv_sg_element *)kzalloc(sizeof(struct ivtv_sg_element), GFP_KERNEL);
225         if (s->sg_dma == NULL) {
226                 IVTV_ERR("Could not allocate sg_dma for %s stream\n", s->name);
227                 kfree(s->sg_pending);
228                 s->sg_pending = NULL;
229                 kfree(s->sg_processing);
230                 s->sg_processing = NULL;
231                 return -ENOMEM;
232         }
233         if (ivtv_might_use_dma(s)) {
234                 s->sg_handle = pci_map_single(itv->dev, s->sg_dma, sizeof(struct ivtv_sg_element), s->dma);
235                 ivtv_stream_sync_for_cpu(s);
236         }
237
238         /* allocate stream buffers. Initially all buffers are in q_free. */
239         for (i = 0; i < s->buffers; i++) {
240                 struct ivtv_buffer *buf = kzalloc(sizeof(struct ivtv_buffer), GFP_KERNEL);
241
242                 if (buf == NULL)
243                         break;
244                 buf->buf = kmalloc(s->buf_size + 256, GFP_KERNEL);
245                 if (buf->buf == NULL) {
246                         kfree(buf);
247                         break;
248                 }
249                 INIT_LIST_HEAD(&buf->list);
250                 if (ivtv_might_use_dma(s)) {
251                         buf->dma_handle = pci_map_single(s->itv->dev,
252                                 buf->buf, s->buf_size + 256, s->dma);
253                         ivtv_buf_sync_for_cpu(s, buf);
254                 }
255                 ivtv_enqueue(s, buf, &s->q_free);
256         }
257         if (i == s->buffers)
258                 return 0;
259         IVTV_ERR("Couldn't allocate buffers for %s stream\n", s->name);
260         ivtv_stream_free(s);
261         return -ENOMEM;
262 }
263
264 void ivtv_stream_free(struct ivtv_stream *s)
265 {
266         struct ivtv_buffer *buf;
267
268         /* move all buffers to q_free */
269         ivtv_flush_queues(s);
270
271         /* empty q_free */
272         while ((buf = ivtv_dequeue(s, &s->q_free))) {
273                 if (ivtv_might_use_dma(s))
274                         pci_unmap_single(s->itv->dev, buf->dma_handle,
275                                 s->buf_size + 256, s->dma);
276                 kfree(buf->buf);
277                 kfree(buf);
278         }
279
280         /* Free SG Array/Lists */
281         if (s->sg_dma != NULL) {
282                 if (s->sg_handle != IVTV_DMA_UNMAPPED) {
283                         pci_unmap_single(s->itv->dev, s->sg_handle,
284                                  sizeof(struct ivtv_sg_element), PCI_DMA_TODEVICE);
285                         s->sg_handle = IVTV_DMA_UNMAPPED;
286                 }
287                 kfree(s->sg_pending);
288                 kfree(s->sg_processing);
289                 kfree(s->sg_dma);
290                 s->sg_pending = NULL;
291                 s->sg_processing = NULL;
292                 s->sg_dma = NULL;
293                 s->sg_pending_size = 0;
294                 s->sg_processing_size = 0;
295         }
296 }