Re: [PATCH] USB: Always map transfer_buffer (Fixes some musb_hdrc issues), take #3

Tony Lindgren <[email protected]>
Newsgroups gmane.linux.usb.devel
Message-ID <[email protected]>
* David Brownell <[email protected]> [070328 14:46]:
> On Wednesday 28 March 2007 9:09 am, Alan Stern wrote:
> > On Wed, 28 Mar 2007, Tony Lindgren wrote:
> > 
> > > Hi,
> > > 
> > > Here's a little patch to make sure tranfer_buffer is always if DMA
> > > is temporarily unavailable. I ran into this with tusb6010 that
> > > currently can only do limited DMA. This fixes a problem of connecting
> > > storage devices and doing mixed DMA/PIO access.
> 
> And isn't that just nasty code, too.  Three different DMA engines,
> three different blocks of unsharable code in the RX and TX paths
> of both host and peripheral side.  Partly that's just nasty code
> leftover from Mentor ... but a lot of it seems to be because of
> some software-unfriendly factoring of the DMA interface.

Yes, yuk!

> > Your patch isn't correct, or at least, it is very misleading.  It calls 
> > page_address() in a situation where it cannot be certain that the page 
> > frame lies in accessible kernel memory.  On some systems the value it 
> > calculates will be garbage.
> 
> That is, the usb_buffer_map_sg() can work on highmem pages (which don't
> tend to exist on ARM!) so that there *is* no valid address to use with
> transfer_buffer.  If you're going to have such code, then it needs to
> encapsulate some "ifdef CONFIG_HIGHMEM" logic to ensure that the current
> behavior applies unless there's no highmem.

OK, attached is take #3 with ifndef CONFIG_HIGHMEM. Anybody have other
limitations in mind?

> ISTR another issue motivating the either/or use of dma/cpu addresses.
> It had to do with the dma unmapping operation ... in some cases it
> will invalidate buffer copies in the CPU cache.  That'd mean that if
> it were appropriate in some case to use the CPU address when a DMA
> address is provided, the lowlevel code should write back those parts
> of the dcache, so that if the unmap invalidates them then the data in
> memory is still correct.

Yeah, the tusb6010_omap.c is already doing dma_sync_single_for_cpu()
or dma_sync_single_for_device() but it may be needed elsewhere too.

Tony

-------------------------------------------------------------------------
Take Surveys. Earn Cash. Influence the Future of IT
Join SourceForge.net's Techsay panel and you'll get the chance to share your
opinions on IT & business topics through brief surveys-and earn cash
http://www.techsay.com/default.php?page=join.php&p=sourceforge&CID=DEVDEV

_______________________________________________
[email protected]
To unsubscribe, use the last form field at:
https://lists.sourceforge.net/lists/listinfo/linux-usb-devel
usb-core-always-map-transfer-buffer.patch (text/x-diff, 1.5 KB)
From: Tony Lindgren <[email protected]>
Subject: USB: Always map transfer_buffer

In case a DMA channel for an endpoint is temporarily
unavailable, the host controller driver may still be
able to transfer the data using PIO. Without this patch
the transfer_buffer is not mapped, and host controller
does not know what to use for PIO.

Signed-off-by: Tony Lindgren <[email protected]>

Index: linux-omap-2.6/drivers/usb/core/message.c
===================================================================
--- linux-omap-2.6.orig/drivers/usb/core/message.c	2007-03-28 10:59:21.000000000 -0400
+++ linux-omap-2.6/drivers/usb/core/message.c	2007-03-28 15:26:59.000000000 -0400
@@ -412,15 +412,23 @@ int usb_sg_init (
 		io->urbs [i]->status = -EINPROGRESS;
 		io->urbs [i]->actual_length = 0;
 
+		/*
+		 * Some systems need both transfer_buffer and transfer_dma
+		 * to revert to PIO if DMA is temporarily unavailable.
+		 * Note that transfer_buffer may not be accessible on some
+		 * systems. In that case there is no need to use it either.
+		 */
 		if (dma) {
-			/* hc may use _only_ transfer_dma */
 			io->urbs [i]->transfer_dma = sg_dma_address (sg + i);
 			len = sg_dma_len (sg + i);
-		} else {
-			/* hc may use _only_ transfer_buffer */
+#ifndef CONFIG_HIGHMEM
 			io->urbs [i]->transfer_buffer =
 				page_address (sg [i].page) + sg [i].offset;
+#endif
+		} else {
 			len = sg [i].length;
+			io->urbs [i]->transfer_buffer =
+				page_address (sg [i].page) + sg [i].offset;
 		}
 
 		if (length) {
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.