aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/media/video/ivtv
diff options
context:
space:
mode:
authorIan Armstrong <ian@iarmst.demon.co.uk>2009-12-21 20:59:26 -0500
committerMauro Carvalho Chehab <mchehab@redhat.com>2010-02-26 13:10:41 -0500
commitb6e436b263b35476da4be06e0719cb1d5c8f8eed (patch)
treeb6055dce972162efde4d3d2748ca7096ee1d68d4 /drivers/media/video/ivtv
parent0726681a7080cef6a9fd414894690fac16418772 (diff)
V4L/DVB: ivtv: Fix race condition for queued udma transfers
There are several DMA related interrupts which wake up the dma_waitq. The udma routines use this queue while they wait for their transfer to complete. When woken, the udma routine will check the IVTV_F_I_UDMA_PENDING & IVTV_F_I_UDMA flags to see if the transfer is still queued or has finished. However, a small window exists between the IVTV_F_I_UDMA_PENDING flag being cleared and the IVTV_F_I_UDMA flag being set. Given that the completion of an unrelated DMA transfer may wake up the udma routine, it's possible for this check to fail and the udma routine will start unmapping pages when the transfer has only just started. The result of this is unpredictable. This fix simply delays the clearing of the IVTV_F_I_UDMA_PENDING flag until after IVTV_F_I_UDMA has been set. Signed-off-by: Ian Armstrong <ian@iarmst.demon.co.uk> Signed-off-by: Andy Walls <awalls@radix.net> Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
Diffstat (limited to 'drivers/media/video/ivtv')
-rw-r--r--drivers/media/video/ivtv/ivtv-irq.c5
-rw-r--r--drivers/media/video/ivtv/ivtv-udma.c1
2 files changed, 4 insertions, 2 deletions
diff --git a/drivers/media/video/ivtv/ivtv-irq.c b/drivers/media/video/ivtv/ivtv-irq.c
index cd9db0bf33bf..ee0cdded69f7 100644
--- a/drivers/media/video/ivtv/ivtv-irq.c
+++ b/drivers/media/video/ivtv/ivtv-irq.c
@@ -940,9 +940,10 @@ irqreturn_t ivtv_irq_handler(int irq, void *dev_id)
940 ivtv_dma_enc_start(s); 940 ivtv_dma_enc_start(s);
941 break; 941 break;
942 } 942 }
943 if (i == IVTV_MAX_STREAMS && test_and_clear_bit(IVTV_F_I_UDMA_PENDING, &itv->i_flags)) { 943
944 if (i == IVTV_MAX_STREAMS &&
945 test_bit(IVTV_F_I_UDMA_PENDING, &itv->i_flags))
944 ivtv_udma_start(itv); 946 ivtv_udma_start(itv);
945 }
946 } 947 }
947 948
948 if ((combo & IVTV_IRQ_DMA) && !test_bit(IVTV_F_I_PIO, &itv->i_flags)) { 949 if ((combo & IVTV_IRQ_DMA) && !test_bit(IVTV_F_I_PIO, &itv->i_flags)) {
diff --git a/drivers/media/video/ivtv/ivtv-udma.c b/drivers/media/video/ivtv/ivtv-udma.c
index d07ad6c39024..1daf1dd65bf7 100644
--- a/drivers/media/video/ivtv/ivtv-udma.c
+++ b/drivers/media/video/ivtv/ivtv-udma.c
@@ -213,6 +213,7 @@ void ivtv_udma_start(struct ivtv *itv)
213 write_reg_sync(read_reg(IVTV_REG_DMAXFER) | 0x01, IVTV_REG_DMAXFER); 213 write_reg_sync(read_reg(IVTV_REG_DMAXFER) | 0x01, IVTV_REG_DMAXFER);
214 set_bit(IVTV_F_I_DMA, &itv->i_flags); 214 set_bit(IVTV_F_I_DMA, &itv->i_flags);
215 set_bit(IVTV_F_I_UDMA, &itv->i_flags); 215 set_bit(IVTV_F_I_UDMA, &itv->i_flags);
216 clear_bit(IVTV_F_I_UDMA_PENDING, &itv->i_flags);
216} 217}
217 218
218void ivtv_udma_prepare(struct ivtv *itv) 219void ivtv_udma_prepare(struct ivtv *itv)