Title: [9802] trunk/drivers/usb/musb: USB: musb: blackfin: work around anomaly 05000450
Revision
9802
Author
vapier
Date
2011-03-28 13:00:58 -0400 (Mon, 28 Mar 2011)

Log Message

USB: musb: blackfin: work around anomaly 05000450

Rewrite the previous patch to use a call back which can be placed
into arch-specific implementations and sent upstream for merging.

Modified Paths

Diff

Modified: trunk/drivers/usb/musb/blackfin.c (9801 => 9802)


--- trunk/drivers/usb/musb/blackfin.c	2011-03-28 09:49:24 UTC (rev 9801)
+++ trunk/drivers/usb/musb/blackfin.c	2011-03-28 17:00:58 UTC (rev 9802)
@@ -21,6 +21,7 @@
 #include <asm/cacheflush.h>
 
 #include "musb_core.h"
+#include "musbhsdma.h"
 #include "blackfin.h"
 
 struct bfin_glue {
@@ -332,6 +333,27 @@
 	return -EIO;
 }
 
+static int bfin_musb_channel_program(struct dma_channel *channel,
+				u16 *packet_sz, u8 *mode,
+				dma_addr_t *dma_addr, u32 *len)
+{
+	struct musb_dma_channel *musb_channel = channel->private_data;
+
+	/*
+	 * Anomaly 05000450 might cause data corruption when using DMA
+	 * MODE 1 transmits with short packet.  So to work around this,
+	 * we truncate all MODE 1 transfers down to a multiple of the
+	 * max packet size, and then do the last short packet transfer
+	 * (if there is any) using MODE 0.
+	 */
+	if (ANOMALY_05000450) {
+		if (musb_channel->transmit && *mode == 1)
+			*len = *len - (*len % *packet_sz);
+	}
+
+	return 0;
+}
+
 static void bfin_musb_reg_init(struct musb *musb)
 {
 	if (ANOMALY_05000346) {
@@ -430,6 +452,8 @@
 
 	.vbus_status	= bfin_musb_vbus_status,
 	.set_vbus	= bfin_musb_set_vbus,
+
+	.channel_program = bfin_musb_channel_program,
 };
 
 static u64 bfin_dmamask = DMA_BIT_MASK(32);

Modified: trunk/drivers/usb/musb/musb_core.h (9801 => 9802)


--- trunk/drivers/usb/musb/musb_core.h	2011-03-28 09:49:24 UTC (rev 9801)
+++ trunk/drivers/usb/musb/musb_core.h	2011-03-28 17:00:58 UTC (rev 9802)
@@ -261,6 +261,7 @@
  * @try_ilde:	tries to idle the IP
  * @vbus_status: returns vbus status if possible
  * @set_vbus:	forces vbus status
+ * @channel_program: pre check for standard dma channel_program func
  */
 struct musb_platform_ops {
 	int	(*init)(struct musb *musb);
@@ -274,6 +275,10 @@
 
 	int	(*vbus_status)(struct musb *musb);
 	void	(*set_vbus)(struct musb *musb, int on);
+
+	int	(*channel_program)(struct dma_channel *channel,
+				u16 *packet_sz, u8 *mode,
+				dma_addr_t *dma_addr, u32 *len);
 };
 
 /*

Modified: trunk/drivers/usb/musb/musb_gadget.c (9801 => 9802)


--- trunk/drivers/usb/musb/musb_gadget.c	2011-03-28 09:49:24 UTC (rev 9801)
+++ trunk/drivers/usb/musb/musb_gadget.c	2011-03-28 17:00:58 UTC (rev 9802)
@@ -384,13 +384,7 @@
 			use_dma = use_dma && c->channel_program(
 					musb_ep->dma, musb_ep->packet_sz,
 					musb_ep->dma->desired_mode,
-					request->dma + request->actual,
-					(musb_ep->dma->desired_mode == 0)
-					? request_size
-					: (request_size -
-					  (request_size %
-					   musb_ep->packet_sz)));
-
+					request->dma + request->actual, request_size);
 			if (use_dma) {
 				if (musb_ep->dma->desired_mode == 0) {
 					/*
@@ -757,11 +751,7 @@
 							channel->desired_mode,
 							request->dma
 							+ request->actual,
-							(musb_ep->dma->desired_mode == 0)
-							? transfer_size
-							: (transfer_size -
-							  (transfer_size %
-							  musb_ep->packet_sz)));
+							transfer_size);
 				}
 
 				if (use_dma)

Modified: trunk/drivers/usb/musb/musb_host.c (9801 => 9802)


--- trunk/drivers/usb/musb/musb_host.c	2011-03-28 09:49:24 UTC (rev 9801)
+++ trunk/drivers/usb/musb/musb_host.c	2011-03-28 17:00:58 UTC (rev 9802)
@@ -672,10 +672,7 @@
 	wmb();
 
 	if (!dma->channel_program(channel, pkt_size, mode,
-			urb->transfer_dma + offset,
-			(channel->desired_mode == 0) ? length :
-				length - (length % qh->maxpacket)))
-	{
+			urb->transfer_dma + offset, length)) {
 		dma->channel_release(channel);
 		hw_ep->tx_channel = NULL;
 
@@ -1753,10 +1750,7 @@
 			 */
 			ret = c->channel_program(
 				dma, qh->maxpacket,
-				dma->desired_mode, buf,
-				(dma->desired_mode == 0)
-				? length
-				: length - (length % qh->maxpacket));
+				dma->desired_mode, buf, length);
 
 			if (!ret) {
 				c->channel_release(dma);

Modified: trunk/drivers/usb/musb/musbhsdma.c (9801 => 9802)


--- trunk/drivers/usb/musb/musbhsdma.c	2011-03-28 09:49:24 UTC (rev 9801)
+++ trunk/drivers/usb/musb/musbhsdma.c	2011-03-28 17:00:58 UTC (rev 9802)
@@ -169,6 +169,14 @@
 	BUG_ON(channel->status == MUSB_DMA_STATUS_UNKNOWN ||
 		channel->status == MUSB_DMA_STATUS_BUSY);
 
+	/* Let targets check/tweak the arguments */
+	if (musb->ops->channel_program) {
+		int ret = musb->ops->channel_program(channel, &packet_sz,
+			&mode, &dma_addr, &len);
+		if (ret)
+			return ret;
+	}
+
 	/*
 	 * The DMA engine in RTL1.8 and above cannot handle
 	 * DMA addresses that are not aligned to a 4 byte boundary.
_______________________________________________
Linux-kernel-commits mailing list
[email protected]
https://blackfin.uclinux.org/mailman/listinfo/linux-kernel-commits

Reply via email to