RE: [PATCH RFC/RFT] MUSB: Do not enable TX and RX DMA at the same time

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

 



Anand Gadiyar wrote:

> MUSB: Do not enable TX and RX DMA at the same time
> 
> This is a workaround for OMAP3 errata 1.130.
> 
> This bug causes an occassional DMA controller hang when
> two DMA channels are simultaneously enabled in RX and TX
> directions.
> 
> With this workaround, in the best case, we effectively use
> DMA in both directions, and in the worst case, we use PIO
> mode in one direction. The average throughput is better
> than using PIO mode in one direction all the time.
> 
> Signed-off-by: Anand Gadiyar <gadiyar@xxxxxx>
> Signed-off-by: Nilkesh Patra <Nilkesh.patra@xxxxxx>
> Signed-off-by: Ajay Kumar Gupta <ajay.gupta@xxxxxx>

Please ignore this patch. I sent out an older version

I'll send an updated one shortly

- Anand


> ---
> - To reproduce the hang condition, use g_ether and start
> pings in both directions - higher ping sizes reproduce the
> failure faster.
> 
> - Needs another patch [1] from me to work reliably.
> 
> [1] <http://marc.info/?l=linux-usb&m=125897074717960&w=2>
> 
> 
> - An alternative workaround for this bug involves using
> the SystemDMA to do a non-synchronized DMA transfer to unload
> the RX FIFO, and use the MUSB DMA for all TX channels.
> If someone wants to use that patch, I can post it as well.
> 
>  drivers/usb/musb/musbhsdma.c |   41 
> +++++++++++++++++++++++++++++++++++++++++
>  drivers/usb/musb/musbhsdma.h |    2 ++
>  2 files changed, 43 insertions(+)
> 
> Index: linux-omap-2.6/drivers/usb/musb/musbhsdma.c
> ===================================================================
> --- linux-omap-2.6.orig/drivers/usb/musb/musbhsdma.c
> +++ linux-omap-2.6/drivers/usb/musb/musbhsdma.c
> @@ -151,6 +151,11 @@ static void configure_channel(struct dma
>  				? (1 << MUSB_HSDMA_TRANSMIT_SHIFT)
>  				: 0);
>  
> +	if (musb_channel->transmit)
> +		controller->tx_active |= (1 << bchannel);
> +	else
> +		controller->rx_active |= (1 << bchannel);
> +
>  	/* address/count */
>  	musb_write_hsdma_addr(mbase, bchannel, dma_addr);
>  	musb_write_hsdma_count(mbase, bchannel, len);
> @@ -161,11 +166,32 @@ static void configure_channel(struct dma
>  		csr);
>  }
>  
> +/* In version 1.4, if two DMA channels are simultaneously
> + * enabled in opposite directions, there is a chance that
> + * the DMA controller will hang. However, it is safe to
> + * use channels in the same direction.
> + * FIXME: provide a better description here
> + */
> +static int musb_okay_to_use_dma(struct musb_dma_controller 
> *controller,
> +					int is_tx)
> +{
> +	struct musb *musb = controller->private_data;
> +
> +	if (musb->hwvers == MUSB_HWVERS_1400) {
> +		if (is_tx && controller->rx_active)
> +			return 0;
> +		else if (!is_tx && controller->tx_active)
> +			return 0;
> +	}
> +	return 1;
> +}
> +
>  static int dma_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;
> +	struct musb_dma_controller *controller = 
> musb_channel->controller;
>  
>  	DBG(2, "ep%d-%s pkt_sz %d, dma_addr 0x%x length %d, mode %d\n",
>  		musb_channel->epnum,
> @@ -175,6 +201,9 @@ static int dma_channel_program(struct dm
>  	BUG_ON(channel->status == MUSB_DMA_STATUS_UNKNOWN ||
>  		channel->status == MUSB_DMA_STATUS_BUSY);
>  
> +	if (!musb_okay_to_use_dma(controller, musb_channel->transmit))
> +		return false;
> +
>  	channel->actual_len = 0;
>  	musb_channel->start_addr = dma_addr;
>  	musb_channel->len = len;
> @@ -229,6 +258,11 @@ static int dma_channel_abort(struct dma_
>  		musb_write_hsdma_addr(mbase, bchannel, 0);
>  		musb_write_hsdma_count(mbase, bchannel, 0);
>  		channel->status = MUSB_DMA_STATUS_FREE;
> +
> +		if (musb_channel->transmit)
> +			musb_channel->controller->tx_active &= 
> ~(1 << bchannel);
> +		else
> +			musb_channel->controller->rx_active &= 
> ~(1 << bchannel);
>  	}
>  
>  	return 0;
> @@ -292,6 +326,13 @@ static irqreturn_t dma_controller_irq(in
>  
>  				channel->status = MUSB_DMA_STATUS_FREE;
>  
> +				if (musb_channel->transmit)
> +					controller->tx_active &=
> +							~(1 << 
> bchannel);
> +				else
> +					controller->rx_active &=
> +							~(1 << 
> bchannel);
> +
>  				/* completed */
>  				if ((devctl & MUSB_DEVCTL_HM)
>  					&& (musb_channel->transmit)
> Index: linux-omap-2.6/drivers/usb/musb/musbhsdma.h
> ===================================================================
> --- linux-omap-2.6.orig/drivers/usb/musb/musbhsdma.h
> +++ linux-omap-2.6/drivers/usb/musb/musbhsdma.h
> @@ -146,4 +146,6 @@ struct musb_dma_controller {
>  	u8				channel_count;
>  	u8				used_channels;
>  	u8				irq;
> +	u8				tx_active;
> +	u8				rx_active;
>  };
> --
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