[oe-commits] org.oe.dev linux omap2 git: add patch to fix musb dma

koen commit oe at amethyst.openembedded.net
Mon Sep 1 18:08:12 UTC 2008


linux omap2 git: add patch to fix musb dma

Author: koen at openembedded.org
Branch: org.openembedded.dev
Revision: 2d19f916b7cff472234f979a8f11d862485c1bd9
ViewMTN: http://monotone.openembedded.org/revision/info/2d19f916b7cff472234f979a8f11d862485c1bd9
Files:
1
packages/linux/linux-omap2-git/beagleboard/musb-dmafix.patch
packages/linux/linux-omap2_git.bb
Diffs:

#
# mt diff -r9b0fbae44184479ffb939c3720d3435cee0db061 -r2d19f916b7cff472234f979a8f11d862485c1bd9
#
#
#
# add_file "packages/linux/linux-omap2-git/beagleboard/musb-dmafix.patch"
#  content [95eea5cc96584fc3e342db6e81d5ad7a88218a80]
# 
# patch "packages/linux/linux-omap2_git.bb"
#  from [87915c4f021c2162daeb74e1fb307a622f4600c6]
#    to [fe0807df08f9b386baae24813ff6aa3f5636acc8]
#
============================================================
--- packages/linux/linux-omap2-git/beagleboard/musb-dmafix.patch	95eea5cc96584fc3e342db6e81d5ad7a88218a80
+++ packages/linux/linux-omap2-git/beagleboard/musb-dmafix.patch	95eea5cc96584fc3e342db6e81d5ad7a88218a80
@@ -0,0 +1,275 @@
+From: Gadiyar, Anand <gadiyar at ti.com>
+Date: Wed, 13 Aug 2008 07:05:29 +0000 (+0530)
+Subject: MUSB: Workaround for simultaneous TX and RX usage
+X-Git-Url: http://git.mansr.com/?p=linux-omap;a=commitdiff_plain;h=2e6aa4efb0e14c51ff0427927b1b38136911fa93
+
+MUSB: Workaround for simultaneous TX and RX usage
+
+MUSB: Workaround for simultaneous TX and RX usage
+
+MUSB RTL V1.4 has a hardware issue which results in a DMA controller
+hang when TX and RX DMA channels are simultaneously enabled. This
+affects at least OMAP2430 and OMAP34XX.
+
+Since RX transfers are in Mode 0 and anyway result in one DMA interrupt
+per packet, we can use System DMA to unload the RX fifos. MUSB DMA can
+be used for all TX channels as before.
+
+Tested with full-duplex TX and RX transfers using g_ether. Runs for 24
+hours without a hang. Without this patch, the hang occurs within minutes.
+
+This issue was first reported by Jon Hunter on [1]
+
+[1] http://marc.info/?l=linux-omap&m=119634480534453&w=2
+
+Signed-off-by: Anand Gadiyar <gadiyar at ti.com>
+---
+
+diff --git a/drivers/usb/musb/Kconfig b/drivers/usb/musb/Kconfig
+index a485a86..8583e54 100644
+--- a/drivers/usb/musb/Kconfig
++++ b/drivers/usb/musb/Kconfig
+@@ -150,6 +150,14 @@ config USB_INVENTRA_DMA
+ 	help
+ 	  Enable DMA transfers using Mentor's engine.
+ 
++config MUSB_USE_SYSTEM_DMA_RX
++	bool 'Use System DMA for RX endpoints'
++	depends on USB_MUSB_HDRC && USB_INVENTRA_DMA
++	help
++	  MUSB RTL version 1.4 has a hardware issue when TX and RX DMA
++	  channels are simultaneously enabled. To work around this issue,
++	  you can choose to use System DMA for RX channels.
++
+ config USB_TI_CPPI_DMA
+ 	bool
+ 	depends on USB_MUSB_HDRC && !MUSB_PIO_ONLY
+diff --git a/drivers/usb/musb/musbhsdma.c b/drivers/usb/musb/musbhsdma.c
+index 32bb1e2..d1c1ea0 100644
+--- a/drivers/usb/musb/musbhsdma.c
++++ b/drivers/usb/musb/musbhsdma.c
+@@ -34,6 +34,7 @@
+ #include <linux/interrupt.h>
+ #include <linux/platform_device.h>
+ #include "musb_core.h"
++#include <asm/arch/dma.h>
+ 
+ #if defined(CONFIG_ARCH_OMAP2430) || defined(CONFIG_ARCH_OMAP3430)
+ #include "omap2430.h"
+@@ -64,6 +65,9 @@
+ 
+ #define MUSB_HSDMA_CHANNELS		8
+ 
++#define MUSB_FIFO_ADDRESS(epnum)	\
++	((unsigned long) (OMAP_HSOTG_BASE + MUSB_FIFO_OFFSET(epnum)))
++
+ struct musb_dma_controller;
+ 
+ struct musb_dma_channel {
+@@ -75,6 +79,8 @@ struct musb_dma_channel {
+ 	u8				bIndex;
+ 	u8				epnum;
+ 	u8				transmit;
++
++	int				sysdma_channel;
+ };
+ 
+ struct musb_dma_controller {
+@@ -93,6 +99,42 @@ static int dma_controller_start(struct dma_controller *c)
+ 	return 0;
+ }
+ 
++#ifdef CONFIG_MUSB_USE_SYSTEM_DMA_RX
++static void musb_sysdma_completion(int lch, u16 ch_status, void *data)
++{
++	u32 dwAddress;
++	unsigned long flags;
++
++	struct dma_channel *pChannel;
++
++	struct musb_dma_channel *pImplChannel =
++					(struct musb_dma_channel *) data;
++	struct musb_dma_controller *controller = pImplChannel->controller;
++	struct musb *musb = controller->pDmaPrivate;
++	pChannel = &pImplChannel->Channel;
++
++	DBG(2, "lch = 0x%d, ch_status = 0x%x\n", lch, ch_status);
++	spin_lock_irqsave(&musb->lock, flags);
++
++	dwAddress = (u32) omap_get_dma_dst_pos(pImplChannel->sysdma_channel);
++	pChannel->actual_len = dwAddress - pImplChannel->dwStartAddress;
++
++	DBG(2, "ch %p, 0x%x -> 0x%x (%d / %d) %s\n",
++		pChannel, pImplChannel->dwStartAddress, dwAddress,
++		pChannel->actual_len, pImplChannel->len,
++		(pChannel->actual_len < pImplChannel->len) ?
++		"=> reconfig 0": "=> complete");
++
++	pChannel->status = MUSB_DMA_STATUS_FREE;
++	musb_dma_completion(musb, pImplChannel->epnum, pImplChannel->transmit);
++
++	spin_unlock_irqrestore(&musb->lock, flags);
++	return;
++}
++#else
++#define musb_sysdma_completion NULL
++#endif
++
+ static void dma_channel_release(struct dma_channel *pChannel);
+ 
+ static int dma_controller_stop(struct dma_controller *c)
+@@ -144,6 +186,29 @@ static struct dma_channel *dma_channel_allocate(struct dma_controller *c,
+ 			/* Tx => mode 1; Rx => mode 0 */
+ 			pChannel->desired_mode = transmit;
+ 			pChannel->actual_len = 0;
++			pImplChannel->sysdma_channel = -1;
++
++#ifdef CONFIG_MUSB_USE_SYSTEM_DMA_RX
++			if (!transmit) {
++				int ret;
++				ret = omap_request_dma(OMAP24XX_DMA_NO_DEVICE,
++					"MUSB SysDMA", musb_sysdma_completion,
++					(void *) pImplChannel,
++					&(pImplChannel->sysdma_channel));
++
++				if (ret) {
++					printk(KERN_ERR "request_dma failed:"
++							" %d\n", ret);
++					controller->bmUsedChannels &=
++								~(1 << bBit);
++					pChannel->status =
++							MUSB_DMA_STATUS_UNKNOWN;
++					pImplChannel->sysdma_channel = -1;
++					pChannel = NULL;
++				}
++			}
++#endif
++
+ 			break;
+ 		}
+ 	}
+@@ -163,6 +228,12 @@ static void dma_channel_release(struct dma_channel *pChannel)
+ 		~(1 << pImplChannel->bIndex);
+ 
+ 	pChannel->status = MUSB_DMA_STATUS_UNKNOWN;
++
++	if (pImplChannel->sysdma_channel != -1) {
++		omap_stop_dma(pImplChannel->sysdma_channel);
++		omap_free_dma(pImplChannel->sysdma_channel);
++		pImplChannel->sysdma_channel = -1;
++	}
+ }
+ 
+ static void configure_channel(struct dma_channel *pChannel,
+@@ -179,41 +250,69 @@ static void configure_channel(struct dma_channel *pChannel,
+ 	DBG(4, "%p, pkt_sz %d, addr 0x%x, len %d, mode %d\n",
+ 			pChannel, packet_sz, dma_addr, len, mode);
+ 
+-	if (mode) {
+-		csr |= 1 << MUSB_HSDMA_MODE1_SHIFT;
+-		BUG_ON(len < packet_sz);
++	if (pImplChannel->sysdma_channel != -1) {
++	/* System DMA */
++	/* RX: set src = FIFO */
++
++		omap_set_dma_transfer_params(pImplChannel->sysdma_channel,
++					OMAP_DMA_DATA_TYPE_S8,
++					len, 1, /* One frame */
++					OMAP_DMA_SYNC_ELEMENT,
++					OMAP24XX_DMA_NO_DEVICE,
++					0); /* Src Sync */
++
++		omap_set_dma_src_params(pImplChannel->sysdma_channel, 0,
++					OMAP_DMA_AMODE_CONSTANT,
++					MUSB_FIFO_ADDRESS(pImplChannel->epnum),
++					0, 0);
+ 
+-		if (packet_sz >= 64) {
+-			csr |= MUSB_HSDMA_BURSTMODE_INCR16
++		omap_set_dma_dest_params(pImplChannel->sysdma_channel, 0,
++					OMAP_DMA_AMODE_POST_INC, dma_addr,
++					0, 0);
++
++		omap_set_dma_dest_data_pack(pImplChannel->sysdma_channel, 1);
++		omap_set_dma_dest_burst_mode(pImplChannel->sysdma_channel,
++					OMAP_DMA_DATA_BURST_16);
++
++		omap_start_dma(pImplChannel->sysdma_channel);
++
++	} else { /* Mentor DMA */
++		if (mode) {
++			csr |= 1 << MUSB_HSDMA_MODE1_SHIFT;
++			BUG_ON(len < packet_sz);
++
++			if (packet_sz >= 64) {
++				csr |= MUSB_HSDMA_BURSTMODE_INCR16
+ 					<< MUSB_HSDMA_BURSTMODE_SHIFT;
+-		} else if (packet_sz >= 32) {
+-			csr |= MUSB_HSDMA_BURSTMODE_INCR8
++			} else if (packet_sz >= 32) {
++				csr |= MUSB_HSDMA_BURSTMODE_INCR8
+ 					<< MUSB_HSDMA_BURSTMODE_SHIFT;
+-		} else if (packet_sz >= 16) {
+-			csr |= MUSB_HSDMA_BURSTMODE_INCR4
++			} else if (packet_sz >= 16) {
++				csr |= MUSB_HSDMA_BURSTMODE_INCR4
+ 					<< MUSB_HSDMA_BURSTMODE_SHIFT;
++			}
+ 		}
+-	}
+ 
+-	csr |= (pImplChannel->epnum << MUSB_HSDMA_ENDPOINT_SHIFT)
+-		| (1 << MUSB_HSDMA_ENABLE_SHIFT)
+-		| (1 << MUSB_HSDMA_IRQENABLE_SHIFT)
+-		| (pImplChannel->transmit
+-				? (1 << MUSB_HSDMA_TRANSMIT_SHIFT)
+-				: 0);
+-
+-	/* address/count */
+-	musb_writel(mbase,
+-		MUSB_HSDMA_CHANNEL_OFFSET(bChannel, MUSB_HSDMA_ADDRESS),
+-		dma_addr);
+-	musb_writel(mbase,
+-		MUSB_HSDMA_CHANNEL_OFFSET(bChannel, MUSB_HSDMA_COUNT),
+-		len);
+-
+-	/* control (this should start things) */
+-	musb_writew(mbase,
+-		MUSB_HSDMA_CHANNEL_OFFSET(bChannel, MUSB_HSDMA_CONTROL),
+-		csr);
++		csr |= (pImplChannel->epnum << MUSB_HSDMA_ENDPOINT_SHIFT)
++			| (1 << MUSB_HSDMA_ENABLE_SHIFT)
++			| (1 << MUSB_HSDMA_IRQENABLE_SHIFT)
++			| (pImplChannel->transmit
++					? (1 << MUSB_HSDMA_TRANSMIT_SHIFT)
++					: 0);
++
++		/* address/count */
++		musb_writel(mbase,
++			MUSB_HSDMA_CHANNEL_OFFSET(bChannel, MUSB_HSDMA_ADDRESS),
++			dma_addr);
++		musb_writel(mbase,
++			MUSB_HSDMA_CHANNEL_OFFSET(bChannel, MUSB_HSDMA_COUNT),
++			len);
++
++		/* control (this should start things) */
++		musb_writew(mbase,
++			MUSB_HSDMA_CHANNEL_OFFSET(bChannel, MUSB_HSDMA_CONTROL),
++			csr);
++	} /* Mentor DMA */
+ }
+ 
+ static int dma_channel_program(struct dma_channel *pChannel,
+@@ -265,6 +364,12 @@ static int dma_channel_abort(struct dma_channel *pChannel)
+ 				MUSB_EP_OFFSET(pImplChannel->epnum, MUSB_TXCSR),
+ 				csr);
+ 		} else {
++			if (pImplChannel->sysdma_channel != -1) {
++				omap_stop_dma(pImplChannel->sysdma_channel);
++				omap_free_dma(pImplChannel->sysdma_channel);
++				pImplChannel->sysdma_channel = -1;
++			}
++
+ 			csr = musb_readw(mbase,
+ 				MUSB_EP_OFFSET(pImplChannel->epnum, MUSB_RXCSR));
+ 			csr &= ~(MUSB_RXCSR_AUTOCLEAR |
============================================================
--- packages/linux/linux-omap2_git.bb	87915c4f021c2162daeb74e1fb307a622f4600c6
+++ packages/linux/linux-omap2_git.bb	fe0807df08f9b386baae24813ff6aa3f5636acc8
@@ -6,7 +6,7 @@ PV = "2.6.26"
 
 PV = "2.6.26"
 #PV = "2.6.26+2.6.27-rc1+${PR}+git${SRCREV}"
-PR = "r60"
+PR = "r61"
 
 SRC_URI = "git://git.kernel.org/pub/scm/linux/kernel/git/tmlind/linux-omap-2.6.git;protocol=git \
 	   file://defconfig"
@@ -52,6 +52,7 @@ SRC_URI_append_beagleboard = " file://no
            file://02-postrate-notifier.eml;patch=1 \
            file://01-omap3-cpufreq.eml;patch=1 \
            file://01-beagle-cpufreq.diff;patch=1 \
+           file://musb-dmafix.patch;patch=1 \ 
 "
 
 SRC_URI_append_omap3evm = " file://no-harry-potter.diff;patch=1 \






More information about the Openembedded-commits mailing list