aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/media/video/ivtv/ivtv-queue.c
diff options
context:
space:
mode:
authorHans Verkuil <hverkuil@xs4all.nl>2007-07-28 18:45:50 -0400
committerMauro Carvalho Chehab <mchehab@infradead.org>2007-10-09 21:05:32 -0400
commit37093b1ea600d84fbf7252baf12eedec85ae40f1 (patch)
treeba78b73933c0d7b8989831c49a86f16c26f99b04 /drivers/media/video/ivtv/ivtv-queue.c
parentf4071b85ea0ca3bd06f63c330562b4cfdffa8473 (diff)
V4L/DVB (6047): ivtv: Fix scatter/gather DMA timeouts
It turns out that the cx23415/6 DMA engine cannot do scatter/gather DMA reliably. Every so often depending on the phase of the moon and your hardware configuration the cx2341x DMA engine simply chokes on it and you have to reboot to get it working again. This change replaced the scatter/gather DMA by single transfers at a time, where the driver is now responsible for DMA-ing each buffer. UDMA is still done using scatter/gather DMA, that will be fixed soon. Many thanks to Mark Bryars <mark.bryars@etvinteractive.com> for discovering the link between scatter/gather and the DMA timeouts. Signed-off-by: Hans Verkuil <hverkuil@xs4all.nl> Signed-off-by: Mauro Carvalho Chehab <mchehab@infradead.org>
Diffstat (limited to 'drivers/media/video/ivtv/ivtv-queue.c')
-rw-r--r--drivers/media/video/ivtv/ivtv-queue.c63
1 files changed, 36 insertions, 27 deletions
diff --git a/drivers/media/video/ivtv/ivtv-queue.c b/drivers/media/video/ivtv/ivtv-queue.c
index bff75aeee0a0..d9a1478ca1f7 100644
--- a/drivers/media/video/ivtv/ivtv-queue.c
+++ b/drivers/media/video/ivtv/ivtv-queue.c
@@ -195,7 +195,7 @@ void ivtv_flush_queues(struct ivtv_stream *s)
195int ivtv_stream_alloc(struct ivtv_stream *s) 195int ivtv_stream_alloc(struct ivtv_stream *s)
196{ 196{
197 struct ivtv *itv = s->itv; 197 struct ivtv *itv = s->itv;
198 int SGsize = sizeof(struct ivtv_SG_element) * s->buffers; 198 int SGsize = sizeof(struct ivtv_sg_element) * s->buffers;
199 int i; 199 int i;
200 200
201 if (s->buffers == 0) 201 if (s->buffers == 0)
@@ -205,27 +205,33 @@ int ivtv_stream_alloc(struct ivtv_stream *s)
205 s->dma != PCI_DMA_NONE ? "DMA " : "", 205 s->dma != PCI_DMA_NONE ? "DMA " : "",
206 s->name, s->buffers, s->buf_size, s->buffers * s->buf_size / 1024); 206 s->name, s->buffers, s->buf_size, s->buffers * s->buf_size / 1024);
207 207
208 if (ivtv_might_use_pio(s)) { 208 s->sg_pending = (struct ivtv_sg_element *)kzalloc(SGsize, GFP_KERNEL);
209 s->PIOarray = (struct ivtv_SG_element *)kzalloc(SGsize, GFP_KERNEL); 209 if (s->sg_pending == NULL) {
210 if (s->PIOarray == NULL) { 210 IVTV_ERR("Could not allocate sg_pending for %s stream\n", s->name);
211 IVTV_ERR("Could not allocate PIOarray for %s stream\n", s->name); 211 return -ENOMEM;
212 return -ENOMEM;
213 }
214 } 212 }
213 s->sg_pending_size = 0;
215 214
216 /* Allocate DMA SG Arrays */ 215 s->sg_processing = (struct ivtv_sg_element *)kzalloc(SGsize, GFP_KERNEL);
217 s->SGarray = (struct ivtv_SG_element *)kzalloc(SGsize, GFP_KERNEL); 216 if (s->sg_processing == NULL) {
218 if (s->SGarray == NULL) { 217 IVTV_ERR("Could not allocate sg_processing for %s stream\n", s->name);
219 IVTV_ERR("Could not allocate SGarray for %s stream\n", s->name); 218 kfree(s->sg_pending);
220 if (ivtv_might_use_pio(s)) { 219 s->sg_pending = NULL;
221 kfree(s->PIOarray); 220 return -ENOMEM;
222 s->PIOarray = NULL; 221 }
223 } 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;
224 return -ENOMEM; 231 return -ENOMEM;
225 } 232 }
226 s->SG_length = 0;
227 if (ivtv_might_use_dma(s)) { 233 if (ivtv_might_use_dma(s)) {
228 s->SG_handle = pci_map_single(itv->dev, s->SGarray, SGsize, s->dma); 234 s->sg_handle = pci_map_single(itv->dev, s->sg_dma, sizeof(struct ivtv_sg_element), s->dma);
229 ivtv_stream_sync_for_cpu(s); 235 ivtv_stream_sync_for_cpu(s);
230 } 236 }
231 237
@@ -272,16 +278,19 @@ void ivtv_stream_free(struct ivtv_stream *s)
272 } 278 }
273 279
274 /* Free SG Array/Lists */ 280 /* Free SG Array/Lists */
275 if (s->SGarray != NULL) { 281 if (s->sg_dma != NULL) {
276 if (s->SG_handle != IVTV_DMA_UNMAPPED) { 282 if (s->sg_handle != IVTV_DMA_UNMAPPED) {
277 pci_unmap_single(s->itv->dev, s->SG_handle, 283 pci_unmap_single(s->itv->dev, s->sg_handle,
278 sizeof(struct ivtv_SG_element) * s->buffers, PCI_DMA_TODEVICE); 284 sizeof(struct ivtv_sg_element), PCI_DMA_TODEVICE);
279 s->SG_handle = IVTV_DMA_UNMAPPED; 285 s->sg_handle = IVTV_DMA_UNMAPPED;
280 } 286 }
281 kfree(s->SGarray); 287 kfree(s->sg_pending);
282 kfree(s->PIOarray); 288 kfree(s->sg_processing);
283 s->PIOarray = NULL; 289 kfree(s->sg_dma);
284 s->SGarray = NULL; 290 s->sg_pending = NULL;
285 s->SG_length = 0; 291 s->sg_processing = NULL;
292 s->sg_dma = NULL;
293 s->sg_pending_size = 0;
294 s->sg_processing_size = 0;
286 } 295 }
287} 296}