Skip to content

Commit

Permalink
USB: musb: blackfin: work around anomaly 05000450
Browse files Browse the repository at this point in the history
DMA mode 1 data corruption anomaly on Blackfin systems.  This issue is
specific to the Blackfin silicon as the bug appears to be related to the
connection of the musb ip to the bus/dma fabric.

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.

Signed-off-by: Mike Frysinger <vapier@gentoo.org>
Signed-off-by: Felipe Balbi <balbi@ti.com>
  • Loading branch information
Mike Frysinger authored and Felipe Balbi committed Apr 13, 2011
1 parent 4f9edd2 commit 1325430
Show file tree
Hide file tree
Showing 3 changed files with 37 additions and 0 deletions.
24 changes: 24 additions & 0 deletions drivers/usb/musb/blackfin.c
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
#include <asm/cacheflush.h>

#include "musb_core.h"
#include "musbhsdma.h"
#include "blackfin.h"

struct bfin_glue {
Expand Down Expand Up @@ -332,6 +333,27 @@ static int bfin_musb_set_mode(struct musb *musb, u8 musb_mode)
return -EIO;
}

static int bfin_musb_adjust_channel_params(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) {
Expand Down Expand Up @@ -430,6 +452,8 @@ static const struct musb_platform_ops bfin_ops = {

.vbus_status = bfin_musb_vbus_status,
.set_vbus = bfin_musb_set_vbus,

.adjust_channel_params = bfin_musb_adjust_channel_params,
};

static u64 bfin_dmamask = DMA_BIT_MASK(32);
Expand Down
5 changes: 5 additions & 0 deletions drivers/usb/musb/musb_core.h
Original file line number Diff line number Diff line change
Expand Up @@ -261,6 +261,7 @@ enum musb_g_ep0_state {
* @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);
Expand All @@ -274,6 +275,10 @@ struct musb_platform_ops {

int (*vbus_status)(struct musb *musb);
void (*set_vbus)(struct musb *musb, int on);

int (*adjust_channel_params)(struct dma_channel *channel,
u16 packet_sz, u8 *mode,
dma_addr_t *dma_addr, u32 *len);
};

/*
Expand Down
8 changes: 8 additions & 0 deletions drivers/usb/musb/musbhsdma.c
Original file line number Diff line number Diff line change
Expand Up @@ -169,6 +169,14 @@ static int dma_channel_program(struct dma_channel *channel,
BUG_ON(channel->status == MUSB_DMA_STATUS_UNKNOWN ||
channel->status == MUSB_DMA_STATUS_BUSY);

/* Let targets check/tweak the arguments */
if (musb->ops->adjust_channel_params) {
int ret = musb->ops->adjust_channel_params(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.
Expand Down

0 comments on commit 1325430

Please sign in to comment.