[PATCH 4/6] [local/generalize] USB: musb: work around Blackfin anomaly 05000450

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

 



From: Bryan Wu <cooloney@xxxxxxxxxx>

DMA mode 1 data corruption anomaly on Blackfin systems

Data corruption when using USB DMA mode 1. (Issue manager 17-01-0105)
DMA mode 1 allows large size transfers to generate a single interrupt
at the end of the entire transfer.  The transfer is split up in packets
of length specified in the Maximum Packet Size field for that endpoint.
If the transfer size is not an integer multiple of the Maximum Packet
Size, a short packet will be present at the end of the transfer.

Under certain conditions this packet may be corrupted in the USB FIFO.

Workaround:
Use DMA mode 1 to transfer (n* Maximum Packet Size) and schedule DMA
mode 0 to transfer the short packet.

As an example if your transfer size is 33168 bytes and Maximum Packet
Size equals 512, schedule [33168 - (33168 mod 512)] in DMA mode 1 and
the remainder (33168 mod 512) in DMA mode 0.

Applies to Revisions: 0.0, 0.1 and 0.2 (BF54x)

Signed-off-by: Bryan Wu <cooloney@xxxxxxxxxx>
Signed-off-by: Cliff Cai <cliff.cai@xxxxxxxxxx>
Signed-off-by: Mike Frysinger <vapier@xxxxxxxxxx>
---
 drivers/usb/musb/musb_gadget.c |   14 ++++++++++++--
 drivers/usb/musb/musb_host.c   |   10 ++++++++--
 2 files changed, 20 insertions(+), 4 deletions(-)

diff --git a/drivers/usb/musb/musb_gadget.c b/drivers/usb/musb/musb_gadget.c
index f4bf6ac..7577094 100644
--- a/drivers/usb/musb/musb_gadget.c
+++ b/drivers/usb/musb/musb_gadget.c
@@ -319,7 +319,13 @@ static void txstate(struct musb *musb, struct musb_request *req)
 			use_dma = use_dma && c->channel_program(
 					musb_ep->dma, musb_ep->packet_sz,
 					musb_ep->dma->desired_mode,
-					request->dma + request->actual, request_size);
+					request->dma + request->actual,
+					(musb_ep->dma->desired_mode == 0)
+					? request_size
+					: (request_size -
+					  (request_size %
+					   musb_ep->packet_sz)));
+
 			if (use_dma) {
 				if (musb_ep->dma->desired_mode == 0) {
 					/*
@@ -680,7 +686,11 @@ static void rxstate(struct musb *musb, struct musb_request *req)
 							channel->desired_mode,
 							request->dma
 							+ request->actual,
-							transfer_size);
+							(musb_ep->dma->desired_mode == 0)
+							? transfer_size
+							: (transfer_size -
+							  (transfer_size %
+							  musb_ep->packet_sz)));
 				}
 
 				if (use_dma)
diff --git a/drivers/usb/musb/musb_host.c b/drivers/usb/musb/musb_host.c
index 39d7a53..9861bc1 100644
--- a/drivers/usb/musb/musb_host.c
+++ b/drivers/usb/musb/musb_host.c
@@ -666,7 +666,10 @@ static bool musb_tx_dma_program(struct dma_controller *dma,
 	qh->segsize = length;
 
 	if (!dma->channel_program(channel, pkt_size, mode,
-			urb->transfer_dma + offset, length)) {
+			urb->transfer_dma + offset,
+			(channel->desired_mode == 0) ? length :
+				length - (length % qh->maxpacket)))
+	{
 		dma->channel_release(channel);
 		hw_ep->tx_channel = NULL;
 
@@ -1741,7 +1744,10 @@ void musb_host_rx(struct musb *musb, u8 epnum)
 			 */
 			ret = c->channel_program(
 				dma, qh->maxpacket,
-				dma->desired_mode, buf, length);
+				dma->desired_mode, buf,
+				(dma->desired_mode == 0)
+				? length
+				: length - (length % qh->maxpacket));
 
 			if (!ret) {
 				c->channel_release(dma);
-- 
1.6.5.4

--
To unsubscribe from this list: send the line "unsubscribe linux-usb" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html

[Index of Archives]     [Linux Media]     [Linux Input]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]     [Old Linux USB Devel Archive]

  Powered by Linux