[PATCH] dma sync fix for FF-cards

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Hi,

according to DMA-API.txt, dma synchronisation must be done before a transfer to the device starts and after a transfer from the device ends. This is missing for the DEBI dma transfer of a FF-card.

-Hartmut

Signed-off-by: Hartmut Birr <e9hack@xxxxxxxxx>
diff -r 6032ecd6ad7e linux/drivers/media/dvb/ttpci/av7110.c
--- a/linux/drivers/media/dvb/ttpci/av7110.c	Sat Aug 30 11:07:04 2008 -0300
+++ b/linux/drivers/media/dvb/ttpci/av7110.c	Sun Aug 31 14:55:29 2008 +0200
@@ -397,6 +397,9 @@ static void debiirq(unsigned long data)
 	switch (type & 0xff) {
 
 	case DATA_TS_RECORD:
+		pci_dma_sync_single_for_cpu(av7110->dev->pci,
+			av7110->debi_bus, 8192, PCI_DMA_FROMDEVICE);
+
 		dvb_dmx_swfilter_packets(&av7110->demux,
 					 (const u8 *) av7110->debi_virt,
 					 av7110->debilen / 188);
@@ -404,6 +407,9 @@ static void debiirq(unsigned long data)
 		break;
 
 	case DATA_PES_RECORD:
+		pci_dma_sync_single_for_cpu(av7110->dev->pci,
+			 av7110->debi_bus, 8192, PCI_DMA_FROMDEVICE);
+
 		if (av7110->demux.recording)
 			av7110_record_cb(&av7110->p2t[handle],
 					 (u8 *) av7110->debi_virt,
@@ -414,6 +420,9 @@ static void debiirq(unsigned long data)
 	case DATA_IPMPE:
 	case DATA_FSECTION:
 	case DATA_PIPING:
+		pci_dma_sync_single_for_cpu(av7110->dev->pci,
+			av7110->debi_bus, 8192, PCI_DMA_FROMDEVICE);
+
 		if (av7110->handle2filter[handle])
 			DvbDmxFilterCallback((u8 *)av7110->debi_virt,
 					     av7110->debilen, NULL, 0,
@@ -425,6 +434,9 @@ static void debiirq(unsigned long data)
 	case DATA_CI_GET:
 	{
 		u8 *data = av7110->debi_virt;
+
+		pci_dma_sync_single_for_cpu(av7110->dev->pci,
+			av7110->debi_bus, 8192, PCI_DMA_FROMDEVICE);
 
 		if ((data[0] < 2) && data[2] == 0xff) {
 			int flags = 0;
@@ -442,6 +454,9 @@ static void debiirq(unsigned long data)
 	}
 
 	case DATA_COMMON_INTERFACE:
+		pci_dma_sync_single_for_cpu(av7110->dev->pci,
+			av7110->debi_bus, 8192, PCI_DMA_FROMDEVICE);
+
 		CI_handle(av7110, (u8 *)av7110->debi_virt, av7110->debilen);
 #if 0 /* keep */
 	{
@@ -462,6 +477,9 @@ static void debiirq(unsigned long data)
 		break;
 
 	case DATA_DEBUG_MESSAGE:
+		pci_dma_sync_single_for_cpu(av7110->dev->pci,
+			av7110->debi_bus, 8192, PCI_DMA_FROMDEVICE);
+
 		((s8*)av7110->debi_virt)[Reserved_SIZE - 1] = 0;
 		printk("%s\n", (s8 *) av7110->debi_virt);
 		xfer = RX_BUFF;
@@ -588,6 +606,9 @@ static void gpioirq(unsigned long data)
 		DVB_RINGBUFFER_SKIP(cibuf, 2);
 
 		dvb_ringbuffer_read(cibuf, av7110->debi_virt, len);
+
+		pci_dma_sync_single_for_device(av7110->dev->pci,
+			av7110->debi_bus, 8192, PCI_DMA_TODEVICE);
 
 		iwdebi(av7110, DEBINOSWAP, TX_LEN, len, 2);
 		iwdebi(av7110, DEBINOSWAP, IRQ_STATE_EXT, len, 2);
@@ -623,6 +644,9 @@ static void gpioirq(unsigned long data)
 			iwdebi(av7110, DEBINOSWAP, TX_BUFF, 0, 2);
 			break;
 		}
+		pci_dma_sync_single_for_device(av7110->dev->pci,
+			av7110->debi_bus, 8192, PCI_DMA_TODEVICE);
+
 		dprintk(8, "GPIO0 PES_PLAY len=%04x\n", len);
 		iwdebi(av7110, DEBINOSWAP, TX_LEN, len, 2);
 		iwdebi(av7110, DEBINOSWAP, IRQ_STATE_EXT, len, 2);
@@ -650,6 +674,8 @@ static void gpioirq(unsigned long data)
 		iwdebi(av7110, DEBINOSWAP, TX_LEN, len, 2);
 		iwdebi(av7110, DEBINOSWAP, IRQ_STATE_EXT, len, 2);
 		memcpy(av7110->debi_virt, av7110->bmpbuf+av7110->bmpp, len);
+		pci_dma_sync_single_for_device(av7110->dev->pci,
+			av7110->debi_bus, 8192, PCI_DMA_TODEVICE);
 		av7110->bmpp += len;
 		av7110->bmplen -= len;
 		dprintk(8, "gpio DATA_BMP_LOAD DMA len %d\n", len);
@@ -2603,7 +2629,7 @@ static int __devinit av7110_attach(struc
 	/* allocate and init buffers */
 	av7110->debi_virt = pci_alloc_consistent(pdev, 8192, &av7110->debi_bus);
 	if (!av7110->debi_virt)
-		goto err_saa71466_vfree_4;
+		goto err_saa7146_vfree_4;
 
 
 	av7110->iobuf = vmalloc(AVOUTLEN+AOUTLEN+BMPLEN+4*IPACKS);
@@ -2688,7 +2714,7 @@ err_iobuf_vfree_6:
 	vfree(av7110->iobuf);
 err_pci_free_5:
 	pci_free_consistent(pdev, 8192, av7110->debi_virt, av7110->debi_bus);
-err_saa71466_vfree_4:
+err_saa7146_vfree_4:
 	if (av7110->grabbing)
 		saa7146_vfree_destroy_pgtable(pdev, av7110->grabbing, &av7110->pt);
 err_i2c_del_3:
Signed-off-by: Hartmut Birr <e9hack@xxxxxxxxx>
diff -r 1760a612cc98 linux/drivers/media/dvb/ttpci/av7110.c
--- a/linux/drivers/media/dvb/ttpci/av7110.c	Sun Aug 03 05:02:35 2008 +0200
+++ b/linux/drivers/media/dvb/ttpci/av7110.c	Sun Aug 31 14:45:44 2008 +0200
@@ -372,10 +372,14 @@ static void processDmaRx(unsigned long d
 	struct av7110 *av7110 = (struct av7110 *) data;
 	int idx;
 
+	/* Ensure streamed PCI data is synced to CPU */
+	pci_dma_sync_single_for_cpu(av7110->dev->pci, av7110->debi_rx_bus,
+				    DMA_RX_BUF_LEN, PCI_DMA_FROMDEVICE);
+
 	while (av7110->rx.debilen[idx = av7110->rx.readIdx]) {
 		int debitype = av7110->rx.debitype[idx];
 		int handle = (debitype >> 8) & 0x1f;
-		u8 *debibuf = av7110->debi_virt + av7110->rx.offset[idx];
+		u8 *debibuf = av7110->debi_rx_virt + av7110->rx.offset[idx];
 		unsigned debilen = av7110->rx.debilen[idx];
 
 		switch (debitype & 0xff) {
@@ -466,7 +470,7 @@ static void fillDmaTx(unsigned long data
 	int len;
 
 	while (! av7110->tx_av.debilen[idx = av7110->tx_av.writeIdx]) {
-		debibuf = av7110->debi_virt + av7110->tx_av.offset[idx];
+		debibuf = av7110->debi_tx_virt + av7110->tx_av.offset[idx];
 		len = av7110_pes_play(debibuf, &av7110->avout, DMA_TX_BUF_SIZE);
 		if (len <= 0)
 			break;
@@ -477,7 +481,7 @@ static void fillDmaTx(unsigned long data
 	}
 
 	while (! av7110->tx_a.debilen[idx = av7110->tx_a.writeIdx]) {
-		debibuf = av7110->debi_virt + av7110->tx_a.offset[idx];
+		debibuf = av7110->debi_tx_virt + av7110->tx_a.offset[idx];
 		len = av7110_pes_play(debibuf, &av7110->aout, DMA_TX_BUF_SIZE);
 		if (len <= 0)
 			break;
@@ -492,7 +496,7 @@ static void fillDmaTx(unsigned long data
 		len = min(av7110->bmplen, DMA_TX_BUF_SIZE);
 		if (len <= 0)
 			break;
-		debibuf = av7110->debi_virt + av7110->tx_bmp.offset[idx];
+		debibuf = av7110->debi_tx_virt + av7110->tx_bmp.offset[idx];
 		memcpy(debibuf, av7110->bmpbuf + av7110->bmpp, len);
 		av7110->bmpp += len;
 		av7110->bmplen -= len;
@@ -501,6 +505,9 @@ static void fillDmaTx(unsigned long data
 			idx = 0;
 		av7110->tx_bmp.writeIdx = idx;
 	}
+	/* Ensure CPU data is synced to the device */
+	pci_dma_sync_single_for_device(av7110->dev->pci, av7110->debi_tx_bus,
+				       DMA_TX_BUF_LEN, PCI_DMA_TODEVICE);
 }
 
 
@@ -801,7 +808,13 @@ static void gpioirq(struct av7110 *av711
 		}
 		DVB_RINGBUFFER_SKIP(cibuf, 2);
 
-		dvb_ringbuffer_read(cibuf, av7110->debi_virt, len);
+		dvb_ringbuffer_read(cibuf, av7110->debi_tx_virt, len);
+
+		/* Ensure CPU data is synced to the device */
+		pci_dma_sync_single_for_device(av7110->dev->pci,
+					       av7110->debi_tx_bus,
+					       DMA_TX_BUF_LEN,
+					       PCI_DMA_TODEVICE);
 
 		iwdebi(av7110, DEBINOSWAP, TX_LEN, len, 2);
 		dprintk(8, "DMA: CI\n");
@@ -2837,19 +2850,26 @@ static int __devinit av7110_attach(struc
 	av7110->arm_thread = NULL;
 
 	/* allocate and init buffers */
-	av7110->debi_virt = pci_alloc_consistent(pdev, DMA_BUF_LEN, &av7110->debi_bus);
-	if (!av7110->debi_virt)
-		goto err_saa71466_vfree_4;
+	av7110->debi_rx_virt = pci_alloc_consistent(pdev, DMA_RX_BUF_LEN,
+						    &av7110->debi_rx_bus);
+	if (!av7110->debi_rx_virt)
+		goto err_saa7146_vfree_4;
+	av7110->debi_tx_virt = pci_alloc_consistent(pdev, DMA_TX_BUF_LEN,
+						    &av7110->debi_tx_bus);
+	if (!av7110->debi_tx_virt)
+		goto err_saa7146_vfree_4a;
 
 	offset = DMA_TX_MISC_BUF_SIZE;
-	for (i = 0; i < DMA_RX_BUFS; i++, offset += DMA_RX_BUF_SIZE)
-		av7110->rx.offset[i] = offset;
 	for (i = 0; i < DMA_TX_AV_BUFS; i++, offset += DMA_TX_BUF_SIZE)
 		av7110->tx_av.offset[i] = offset;
 	for (i = 0; i < DMA_TX_A_BUFS; i++, offset += DMA_TX_BUF_SIZE)
 		av7110->tx_a.offset[i] = offset;
 	for (i = 0; i < DMA_TX_BMP_BUFS; i++, offset += DMA_TX_BUF_SIZE)
 		av7110->tx_bmp.offset[i] = offset;
+
+	offset = 0;
+	for (i = 0; i < DMA_RX_BUFS; i++, offset += DMA_RX_BUF_SIZE)
+		av7110->rx.offset[i] = offset;
 
 	av7110->iobuf = vmalloc(AVOUTLEN+AOUTLEN+BMPLEN+4*IPACKS);
 	if (!av7110->iobuf)
@@ -2932,8 +2952,12 @@ err_iobuf_vfree_6:
 err_iobuf_vfree_6:
 	vfree(av7110->iobuf);
 err_pci_free_5:
-	pci_free_consistent(pdev, DMA_BUF_LEN, av7110->debi_virt, av7110->debi_bus);
-err_saa71466_vfree_4:
+	pci_free_consistent(pdev, DMA_TX_BUF_LEN,
+			    av7110->debi_tx_virt, av7110->debi_tx_bus);
+err_saa7146_vfree_4a:
+	pci_free_consistent(pdev, DMA_RX_BUF_LEN,
+			    av7110->debi_rx_virt, av7110->debi_rx_bus);
+err_saa7146_vfree_4:
 	if (av7110->grabbing)
 		saa7146_vfree_destroy_pgtable(pdev, av7110->grabbing, &av7110->pt);
 err_i2c_del_3:
@@ -2985,8 +3009,10 @@ static int __devexit av7110_detach(struc
 	av7110_av_exit(av7110);
 
 	vfree(av7110->iobuf);
-	pci_free_consistent(saa->pci, DMA_BUF_LEN, av7110->debi_virt,
-			    av7110->debi_bus);
+	pci_free_consistent(saa->pci, DMA_RX_BUF_LEN, av7110->debi_rx_virt,
+			    av7110->debi_rx_bus);
+	pci_free_consistent(saa->pci, DMA_TX_BUF_LEN, av7110->debi_tx_virt,
+			    av7110->debi_tx_bus);
 
 	i2c_del_adapter(&av7110->i2c_adap);
 
diff -r 1760a612cc98 linux/drivers/media/dvb/ttpci/av7110.h
--- a/linux/drivers/media/dvb/ttpci/av7110.h	Sun Aug 03 05:02:35 2008 +0200
+++ b/linux/drivers/media/dvb/ttpci/av7110.h	Sun Aug 31 14:45:44 2008 +0200
@@ -104,11 +104,11 @@ struct infrared {
 #define DMA_TX_BMP_BUFS		3	/* TX bitmap */
 #define DMA_MAX_TX_BUFS		5	/* maximum of the above */
 #define DMA_TX_MISC_BUF_SIZE	0x800	/* TX everything else */
-#define DMA_BUF_LEN		( DMA_TX_MISC_BUF_SIZE			\
-				+ DMA_RX_BUFS * DMA_RX_BUF_SIZE		\
+#define DMA_RX_BUF_LEN		(DMA_RX_BUFS * DMA_RX_BUF_SIZE)
+#define DMA_TX_BUF_LEN		(DMA_TX_MISC_BUF_SIZE			\
 				+ DMA_TX_A_BUFS * DMA_TX_BUF_SIZE	\
 				+ DMA_TX_AV_BUFS * DMA_TX_BUF_SIZE	\
-				+ DMA_TX_BMP_BUFS * DMA_TX_BUF_SIZE )
+				+ DMA_TX_BMP_BUFS * DMA_TX_BUF_SIZE)
 
 struct dma_rx {
 	unsigned	readIdx;
@@ -266,8 +266,10 @@ struct av7110 {
 	u16		    arm_loops;
 
 	/* DMA buffers */
-	void			*debi_virt;
-	dma_addr_t		debi_bus;
+	void			*debi_rx_virt;
+	void			*debi_tx_virt;
+	dma_addr_t		debi_rx_bus;
+	dma_addr_t		debi_tx_bus;
 	struct dma_rx		rx;
 	struct tasklet_struct	rx_tasklet;
 	struct dma_tx		tx_a;
diff -r 1760a612cc98 linux/drivers/media/dvb/ttpci/av7110_hw.c
--- a/linux/drivers/media/dvb/ttpci/av7110_hw.c	Sun Aug 03 05:02:35 2008 +0200
+++ b/linux/drivers/media/dvb/ttpci/av7110_hw.c	Sun Aug 31 14:45:44 2008 +0200
@@ -64,7 +64,7 @@ int av7110_debiwrite(struct av7110 *av71
 	if (count <= 4)		/* immediate transfer */
 		saa7146_write(dev, DEBI_AD, val);
 	else			/* block transfer */
-		saa7146_write(dev, DEBI_AD, av7110->debi_bus + offset);
+		saa7146_write(dev, DEBI_AD, av7110->debi_tx_bus + offset);
 	saa7146_write(dev, DEBI_COMMAND, (count << 17) | (addr & 0xffff));
 	saa7146_write(dev, MC2, (2 << 16) | 2);
 	return 0;
@@ -84,7 +84,7 @@ u32 av7110_debiread(struct av7110 *av711
 		printk("%s: wait_for_debi_done #1 failed\n", __func__);
 		return 0;
 	}
-	saa7146_write(dev, DEBI_AD, av7110->debi_bus + offset);
+	saa7146_write(dev, DEBI_AD, av7110->debi_rx_bus + offset);
 	saa7146_write(dev, DEBI_COMMAND, (count << 17) | 0x10000 | (addr & 0xffff));
 
 	saa7146_write(dev, DEBI_CONFIG, config);
diff -r 1760a612cc98 linux/drivers/media/dvb/ttpci/av7110_hw.h
--- a/linux/drivers/media/dvb/ttpci/av7110_hw.h	Sun Aug 03 05:02:35 2008 +0200
+++ b/linux/drivers/media/dvb/ttpci/av7110_hw.h	Sun Aug 31 14:45:44 2008 +0200
@@ -392,7 +392,9 @@ static inline void iwdebi(struct av7110 
 /* buffer writes */
 static inline void mwdebi(struct av7110 *av7110, u32 config, int addr, u8 *val, int count)
 {
-	memcpy(av7110->debi_virt, val, count);
+	memcpy(av7110->debi_tx_virt, val, count);
+	pci_dma_sync_single_for_device(av7110->dev->pci, av7110->debi_tx_bus,
+				       DMA_TX_BUF_LEN, PCI_DMA_TODEVICE);
 	av7110_debiwrite(av7110, config, 0, addr, 0, count);
 }
 
_______________________________________________
linux-dvb mailing list
linux-dvb@xxxxxxxxxxx
http://www.linuxtv.org/cgi-bin/mailman/listinfo/linux-dvb

[Index of Archives]     [Linux Media]     [Video 4 Linux]     [Asterisk]     [Samba]     [Xorg]     [Xfree86]     [Linux USB]

  Powered by Linux