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