Commit | Line | Data |
---|---|---|
1a0adaf3 HV |
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" | |
1a0adaf3 | 23 | #include "ivtv-queue.h" |
1a0adaf3 HV |
24 | |
25 | int ivtv_buf_copy_from_user(struct ivtv_stream *s, struct ivtv_buffer *buf, const char __user *src, int copybytes) | |
26 | { | |
27 | if (s->buf_size - buf->bytesused < copybytes) | |
28 | copybytes = s->buf_size - buf->bytesused; | |
29 | if (copy_from_user(buf->buf + buf->bytesused, src, copybytes)) { | |
30 | return -EFAULT; | |
31 | } | |
32 | buf->bytesused += copybytes; | |
33 | return copybytes; | |
34 | } | |
35 | ||
36 | void ivtv_buf_swap(struct ivtv_buffer *buf) | |
37 | { | |
38 | int i; | |
39 | ||
40 | for (i = 0; i < buf->bytesused; i += 4) | |
41 | swab32s((u32 *)(buf->buf + i)); | |
42 | } | |
43 | ||
44 | void ivtv_queue_init(struct ivtv_queue *q) | |
45 | { | |
46 | INIT_LIST_HEAD(&q->list); | |
47 | q->buffers = 0; | |
48 | q->length = 0; | |
49 | q->bytesused = 0; | |
50 | } | |
51 | ||
52 | void ivtv_enqueue(struct ivtv_stream *s, struct ivtv_buffer *buf, struct ivtv_queue *q) | |
53 | { | |
7daa4a88 | 54 | unsigned long flags; |
1a0adaf3 HV |
55 | |
56 | /* clear the buffer if it is going to be enqueued to the free queue */ | |
57 | if (q == &s->q_free) { | |
58 | buf->bytesused = 0; | |
59 | buf->readpos = 0; | |
60 | buf->b_flags = 0; | |
f4071b85 | 61 | buf->dma_xfer_cnt = 0; |
1a0adaf3 HV |
62 | } |
63 | spin_lock_irqsave(&s->qlock, flags); | |
64 | list_add_tail(&buf->list, &q->list); | |
65 | q->buffers++; | |
66 | q->length += s->buf_size; | |
67 | q->bytesused += buf->bytesused - buf->readpos; | |
68 | spin_unlock_irqrestore(&s->qlock, flags); | |
69 | } | |
70 | ||
71 | struct ivtv_buffer *ivtv_dequeue(struct ivtv_stream *s, struct ivtv_queue *q) | |
72 | { | |
73 | struct ivtv_buffer *buf = NULL; | |
7daa4a88 | 74 | unsigned long flags; |
1a0adaf3 HV |
75 | |
76 | spin_lock_irqsave(&s->qlock, flags); | |
77 | if (!list_empty(&q->list)) { | |
78 | buf = list_entry(q->list.next, struct ivtv_buffer, list); | |
79 | list_del_init(q->list.next); | |
80 | q->buffers--; | |
81 | q->length -= s->buf_size; | |
82 | q->bytesused -= buf->bytesused - buf->readpos; | |
83 | } | |
84 | spin_unlock_irqrestore(&s->qlock, flags); | |
85 | return buf; | |
86 | } | |
87 | ||
88 | static void ivtv_queue_move_buf(struct ivtv_stream *s, struct ivtv_queue *from, | |
f4071b85 | 89 | struct ivtv_queue *to, int clear) |
1a0adaf3 HV |
90 | { |
91 | struct ivtv_buffer *buf = list_entry(from->list.next, struct ivtv_buffer, list); | |
92 | ||
93 | list_move_tail(from->list.next, &to->list); | |
94 | from->buffers--; | |
95 | from->length -= s->buf_size; | |
96 | from->bytesused -= buf->bytesused - buf->readpos; | |
97 | /* special handling for q_free */ | |
98 | if (clear) | |
f4071b85 | 99 | buf->bytesused = buf->readpos = buf->b_flags = buf->dma_xfer_cnt = 0; |
1a0adaf3 HV |
100 | to->buffers++; |
101 | to->length += s->buf_size; | |
102 | to->bytesused += buf->bytesused - buf->readpos; | |
103 | } | |
104 | ||
105 | /* Move 'needed_bytes' worth of buffers from queue 'from' into queue 'to'. | |
106 | If 'needed_bytes' == 0, then move all buffers from 'from' into 'to'. | |
107 | If 'steal' != NULL, then buffers may also taken from that queue if | |
f4071b85 | 108 | needed, but only if 'from' is the free queue. |
1a0adaf3 HV |
109 | |
110 | The buffer is automatically cleared if it goes to the free queue. It is | |
111 | also cleared if buffers need to be taken from the 'steal' queue and | |
112 | the 'from' queue is the free queue. | |
113 | ||
114 | When 'from' is q_free, then needed_bytes is compared to the total | |
115 | available buffer length, otherwise needed_bytes is compared to the | |
116 | bytesused value. For the 'steal' queue the total available buffer | |
117 | length is always used. | |
118 | ||
119 | -ENOMEM is returned if the buffers could not be obtained, 0 if all | |
120 | buffers where obtained from the 'from' list and if non-zero then | |
121 | the number of stolen buffers is returned. */ | |
122 | int ivtv_queue_move(struct ivtv_stream *s, struct ivtv_queue *from, struct ivtv_queue *steal, | |
123 | struct ivtv_queue *to, int needed_bytes) | |
124 | { | |
125 | unsigned long flags; | |
126 | int rc = 0; | |
127 | int from_free = from == &s->q_free; | |
128 | int to_free = to == &s->q_free; | |
f4071b85 | 129 | int bytes_available, bytes_steal; |
1a0adaf3 HV |
130 | |
131 | spin_lock_irqsave(&s->qlock, flags); | |
132 | if (needed_bytes == 0) { | |
133 | from_free = 1; | |
134 | needed_bytes = from->length; | |
135 | } | |
136 | ||
137 | bytes_available = from_free ? from->length : from->bytesused; | |
f4071b85 | 138 | bytes_steal = (from_free && steal) ? steal->length : 0; |
1a0adaf3 | 139 | |
f4071b85 | 140 | if (bytes_available + bytes_steal < needed_bytes) { |
1a0adaf3 HV |
141 | spin_unlock_irqrestore(&s->qlock, flags); |
142 | return -ENOMEM; | |
143 | } | |
f4071b85 HV |
144 | while (bytes_available < needed_bytes) { |
145 | struct ivtv_buffer *buf = list_entry(steal->list.prev, struct ivtv_buffer, list); | |
146 | u16 dma_xfer_cnt = buf->dma_xfer_cnt; | |
147 | ||
148 | /* move buffers from the tail of the 'steal' queue to the tail of the | |
149 | 'from' queue. Always copy all the buffers with the same dma_xfer_cnt | |
150 | value, this ensures that you do not end up with partial frame data | |
151 | if one frame is stored in multiple buffers. */ | |
152 | while (dma_xfer_cnt == buf->dma_xfer_cnt) { | |
153 | list_move_tail(steal->list.prev, &from->list); | |
154 | rc++; | |
155 | steal->buffers--; | |
156 | steal->length -= s->buf_size; | |
157 | steal->bytesused -= buf->bytesused - buf->readpos; | |
158 | buf->bytesused = buf->readpos = buf->b_flags = buf->dma_xfer_cnt = 0; | |
159 | from->buffers++; | |
160 | from->length += s->buf_size; | |
161 | bytes_available += s->buf_size; | |
162 | if (list_empty(&steal->list)) | |
163 | break; | |
164 | buf = list_entry(steal->list.prev, struct ivtv_buffer, list); | |
165 | } | |
166 | } | |
1a0adaf3 HV |
167 | if (from_free) { |
168 | u32 old_length = to->length; | |
169 | ||
170 | while (to->length - old_length < needed_bytes) { | |
f4071b85 | 171 | ivtv_queue_move_buf(s, from, to, 1); |
1a0adaf3 HV |
172 | } |
173 | } | |
174 | else { | |
175 | u32 old_bytesused = to->bytesused; | |
176 | ||
177 | while (to->bytesused - old_bytesused < needed_bytes) { | |
f4071b85 | 178 | ivtv_queue_move_buf(s, from, to, to_free); |
1a0adaf3 HV |
179 | } |
180 | } | |
181 | spin_unlock_irqrestore(&s->qlock, flags); | |
182 | return rc; | |
183 | } | |
184 | ||
185 | void ivtv_flush_queues(struct ivtv_stream *s) | |
186 | { | |
187 | ivtv_queue_move(s, &s->q_io, NULL, &s->q_free, 0); | |
188 | ivtv_queue_move(s, &s->q_full, NULL, &s->q_free, 0); | |
189 | ivtv_queue_move(s, &s->q_dma, NULL, &s->q_free, 0); | |
190 | ivtv_queue_move(s, &s->q_predma, NULL, &s->q_free, 0); | |
191 | } | |
192 | ||
193 | int ivtv_stream_alloc(struct ivtv_stream *s) | |
194 | { | |
195 | struct ivtv *itv = s->itv; | |
b0510f8d | 196 | int SGsize = sizeof(struct ivtv_sg_host_element) * s->buffers; |
1a0adaf3 HV |
197 | int i; |
198 | ||
199 | if (s->buffers == 0) | |
200 | return 0; | |
201 | ||
202 | IVTV_DEBUG_INFO("Allocate %s%s stream: %d x %d buffers (%dkB total)\n", | |
203 | s->dma != PCI_DMA_NONE ? "DMA " : "", | |
204 | s->name, s->buffers, s->buf_size, s->buffers * s->buf_size / 1024); | |
205 | ||
3f98387e | 206 | s->sg_pending = kzalloc(SGsize, GFP_KERNEL|__GFP_NOWARN); |
37093b1e HV |
207 | if (s->sg_pending == NULL) { |
208 | IVTV_ERR("Could not allocate sg_pending for %s stream\n", s->name); | |
209 | return -ENOMEM; | |
dc02d50a | 210 | } |
37093b1e | 211 | s->sg_pending_size = 0; |
dc02d50a | 212 | |
3f98387e | 213 | s->sg_processing = kzalloc(SGsize, GFP_KERNEL|__GFP_NOWARN); |
37093b1e HV |
214 | if (s->sg_processing == NULL) { |
215 | IVTV_ERR("Could not allocate sg_processing for %s stream\n", s->name); | |
216 | kfree(s->sg_pending); | |
217 | s->sg_pending = NULL; | |
218 | return -ENOMEM; | |
219 | } | |
220 | s->sg_processing_size = 0; | |
221 | ||
3f98387e HV |
222 | s->sg_dma = kzalloc(sizeof(struct ivtv_sg_element), |
223 | GFP_KERNEL|__GFP_NOWARN); | |
37093b1e HV |
224 | if (s->sg_dma == NULL) { |
225 | IVTV_ERR("Could not allocate sg_dma for %s stream\n", s->name); | |
226 | kfree(s->sg_pending); | |
227 | s->sg_pending = NULL; | |
228 | kfree(s->sg_processing); | |
229 | s->sg_processing = NULL; | |
dc02d50a HV |
230 | return -ENOMEM; |
231 | } | |
dc02d50a | 232 | if (ivtv_might_use_dma(s)) { |
e9e10124 AC |
233 | s->sg_handle = pci_map_single(itv->pdev, s->sg_dma, |
234 | sizeof(struct ivtv_sg_element), PCI_DMA_TODEVICE); | |
1a0adaf3 HV |
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++) { | |
3f98387e HV |
240 | struct ivtv_buffer *buf = kzalloc(sizeof(struct ivtv_buffer), |
241 | GFP_KERNEL|__GFP_NOWARN); | |
1a0adaf3 HV |
242 | |
243 | if (buf == NULL) | |
244 | break; | |
3f98387e | 245 | buf->buf = kmalloc(s->buf_size + 256, GFP_KERNEL|__GFP_NOWARN); |
1a0adaf3 HV |
246 | if (buf->buf == NULL) { |
247 | kfree(buf); | |
248 | break; | |
249 | } | |
250 | INIT_LIST_HEAD(&buf->list); | |
dc02d50a | 251 | if (ivtv_might_use_dma(s)) { |
8ac05ae3 | 252 | buf->dma_handle = pci_map_single(s->itv->pdev, |
1a0adaf3 HV |
253 | buf->buf, s->buf_size + 256, s->dma); |
254 | ivtv_buf_sync_for_cpu(s, buf); | |
255 | } | |
256 | ivtv_enqueue(s, buf, &s->q_free); | |
257 | } | |
258 | if (i == s->buffers) | |
259 | return 0; | |
260 | IVTV_ERR("Couldn't allocate buffers for %s stream\n", s->name); | |
261 | ivtv_stream_free(s); | |
262 | return -ENOMEM; | |
263 | } | |
264 | ||
265 | void ivtv_stream_free(struct ivtv_stream *s) | |
266 | { | |
267 | struct ivtv_buffer *buf; | |
268 | ||
269 | /* move all buffers to q_free */ | |
270 | ivtv_flush_queues(s); | |
271 | ||
272 | /* empty q_free */ | |
273 | while ((buf = ivtv_dequeue(s, &s->q_free))) { | |
dc02d50a | 274 | if (ivtv_might_use_dma(s)) |
8ac05ae3 | 275 | pci_unmap_single(s->itv->pdev, buf->dma_handle, |
1a0adaf3 HV |
276 | s->buf_size + 256, s->dma); |
277 | kfree(buf->buf); | |
278 | kfree(buf); | |
279 | } | |
280 | ||
281 | /* Free SG Array/Lists */ | |
37093b1e HV |
282 | if (s->sg_dma != NULL) { |
283 | if (s->sg_handle != IVTV_DMA_UNMAPPED) { | |
8ac05ae3 | 284 | pci_unmap_single(s->itv->pdev, s->sg_handle, |
37093b1e HV |
285 | sizeof(struct ivtv_sg_element), PCI_DMA_TODEVICE); |
286 | s->sg_handle = IVTV_DMA_UNMAPPED; | |
1a0adaf3 | 287 | } |
37093b1e HV |
288 | kfree(s->sg_pending); |
289 | kfree(s->sg_processing); | |
290 | kfree(s->sg_dma); | |
291 | s->sg_pending = NULL; | |
292 | s->sg_processing = NULL; | |
293 | s->sg_dma = NULL; | |
294 | s->sg_pending_size = 0; | |
295 | s->sg_processing_size = 0; | |
1a0adaf3 HV |
296 | } |
297 | } |