diff mbox

[U-Boot,3/5] usb: ehci: Implement V2P mapping

Message ID 1453860843-5835-3-git-send-email-marex@denx.de
State Accepted
Commit cf7c93cdd75570fe6f75d04177b94a84146f5e46
Delegated to: Marek Vasut
Headers show

Commit Message

Marek Vasut Jan. 27, 2016, 2:14 a.m. UTC
Certain processor architectures, like MIPS, require that the USB
structures and transfer buffers are passed with their PA to the
USB controller. If VA is passed, the USB will not work. Add the
necessary virt_to_phys() calls into the USB EHCI code to make it
work.

Signed-off-by: Marek Vasut <marex@denx.de>
Cc: Daniel Schwierzeck <daniel.schwierzeck@gmail.com>
Cc: Hans de Goede <hdegoede@redhat.com>
---
 drivers/usb/host/ehci-hcd.c | 19 +++++++++----------
 1 file changed, 9 insertions(+), 10 deletions(-)

Comments

Stephen Warren Feb. 26, 2016, 4:48 p.m. UTC | #1
On 01/26/2016 07:14 PM, Marek Vasut wrote:
> Certain processor architectures, like MIPS, require that the USB
> structures and transfer buffers are passed with their PA to the
> USB controller. If VA is passed, the USB will not work. Add the
> necessary virt_to_phys() calls into the USB EHCI code to make it
> work.

FYI, this causes some cast size warnings, e.g.:

> +make O=/home/swarren/shared/git_wa/tegra-uboot-flasher/u-boot/build-p2371-2180 -s p2371-2180_defconfig
> +make O=/home/swarren/shared/git_wa/tegra-uboot-flasher/u-boot/build-p2371-2180 -s -j8
> In file included from ../arch/arm/include/asm/byteorder.h:29:0,
>                  from ../include/compiler.h:125,
>                  from ../include/image.h:19,
>                  from ../include/common.h:88,
>                  from ../drivers/usb/host/ehci-hcd.c:10:
> ../drivers/usb/host/ehci-hcd.c: In function ‘ehci_td_buffer’:
> ../drivers/usb/host/ehci-hcd.c:248:49: warning: cast to pointer from integer of different size [-Wint-to-pointer-cast]
>    td->qt_buffer[idx] = cpu_to_hc32(virt_to_phys((void *)addr));
>                                                  ^
> ../include/linux/byteorder/little_endian.h:34:51: note: in definition of macro ‘__cpu_to_le32’
>  #define __cpu_to_le32(x) ((__force __le32)(__u32)(x))
>                                                    ^
> ../drivers/usb/host/ehci-hcd.c:248:24: note: in expansion of macro ‘cpu_to_hc32’
>    td->qt_buffer[idx] = cpu_to_hc32(virt_to_phys((void *)addr));
>                         ^

(This is a 64-bit ARM platform, so I had CROSS_COMPILE=aarch64-linux-gnu-)
Marek Vasut Feb. 26, 2016, 4:55 p.m. UTC | #2
On 02/26/2016 05:48 PM, Stephen Warren wrote:
> On 01/26/2016 07:14 PM, Marek Vasut wrote:
>> Certain processor architectures, like MIPS, require that the USB
>> structures and transfer buffers are passed with their PA to the
>> USB controller. If VA is passed, the USB will not work. Add the
>> necessary virt_to_phys() calls into the USB EHCI code to make it
>> work.
> 
> FYI, this causes some cast size warnings, e.g.:
> 
>> +make
>> O=/home/swarren/shared/git_wa/tegra-uboot-flasher/u-boot/build-p2371-2180
>> -s p2371-2180_defconfig
>> +make
>> O=/home/swarren/shared/git_wa/tegra-uboot-flasher/u-boot/build-p2371-2180
>> -s -j8
>> In file included from ../arch/arm/include/asm/byteorder.h:29:0,
>>                  from ../include/compiler.h:125,
>>                  from ../include/image.h:19,
>>                  from ../include/common.h:88,
>>                  from ../drivers/usb/host/ehci-hcd.c:10:
>> ../drivers/usb/host/ehci-hcd.c: In function ‘ehci_td_buffer’:
>> ../drivers/usb/host/ehci-hcd.c:248:49: warning: cast to pointer from
>> integer of different size [-Wint-to-pointer-cast]
>>    td->qt_buffer[idx] = cpu_to_hc32(virt_to_phys((void *)addr));
>>                                                  ^
>> ../include/linux/byteorder/little_endian.h:34:51: note: in definition
>> of macro ‘__cpu_to_le32’
>>  #define __cpu_to_le32(x) ((__force __le32)(__u32)(x))
>>                                                    ^
>> ../drivers/usb/host/ehci-hcd.c:248:24: note: in expansion of macro
>> ‘cpu_to_hc32’
>>    td->qt_buffer[idx] = cpu_to_hc32(virt_to_phys((void *)addr));
>>                         ^
> 
> (This is a 64-bit ARM platform, so I had CROSS_COMPILE=aarch64-linux-gnu-)

Tom reported this to me too, sorry :-(

Do you have an idea how to fix this too? I am now installing arm64
toolchain.

Do you know about some nice arm64 board with USB for testing?
Stephen Warren Feb. 26, 2016, 6:16 p.m. UTC | #3
On 02/26/2016 09:55 AM, Marek Vasut wrote:
> On 02/26/2016 05:48 PM, Stephen Warren wrote:
>> On 01/26/2016 07:14 PM, Marek Vasut wrote:
>>> Certain processor architectures, like MIPS, require that the USB
>>> structures and transfer buffers are passed with their PA to the
>>> USB controller. If VA is passed, the USB will not work. Add the
>>> necessary virt_to_phys() calls into the USB EHCI code to make it
>>> work.
>>
>> FYI, this causes some cast size warnings, e.g.:
>>
>>> +make
>>> O=/home/swarren/shared/git_wa/tegra-uboot-flasher/u-boot/build-p2371-2180
>>> -s p2371-2180_defconfig
>>> +make
>>> O=/home/swarren/shared/git_wa/tegra-uboot-flasher/u-boot/build-p2371-2180
>>> -s -j8
>>> In file included from ../arch/arm/include/asm/byteorder.h:29:0,
>>>                   from ../include/compiler.h:125,
>>>                   from ../include/image.h:19,
>>>                   from ../include/common.h:88,
>>>                   from ../drivers/usb/host/ehci-hcd.c:10:
>>> ../drivers/usb/host/ehci-hcd.c: In function ‘ehci_td_buffer’:
>>> ../drivers/usb/host/ehci-hcd.c:248:49: warning: cast to pointer from
>>> integer of different size [-Wint-to-pointer-cast]
>>>     td->qt_buffer[idx] = cpu_to_hc32(virt_to_phys((void *)addr));
>>>                                                   ^
>>> ../include/linux/byteorder/little_endian.h:34:51: note: in definition
>>> of macro ‘__cpu_to_le32’
>>>   #define __cpu_to_le32(x) ((__force __le32)(__u32)(x))
>>>                                                     ^
>>> ../drivers/usb/host/ehci-hcd.c:248:24: note: in expansion of macro
>>> ‘cpu_to_hc32’
>>>     td->qt_buffer[idx] = cpu_to_hc32(virt_to_phys((void *)addr));
>>>                          ^
>>
>> (This is a 64-bit ARM platform, so I had CROSS_COMPILE=aarch64-linux-gnu-)
>
> Tom reported this to me too, sorry :-(
>
> Do you have an idea how to fix this too? I am now installing arm64
> toolchain.

I haven't looked at it yet. I've seen similar problems in the bast 
handled by casting between integer types before casting to pointers e.g. 
something like the following guess:

uint32_t pa;
void *p = (void *)(uintptr_t)pa;

> Do you know about some nice arm64 board with USB for testing?

There's always the Jetson TX1; it is the p2371-2180 that I was building 
above:

http://www.nvidia.com/object/jetson-tx1-dev-kit.html
diff mbox

Patch

diff --git a/drivers/usb/host/ehci-hcd.c b/drivers/usb/host/ehci-hcd.c
index c664b16..b3eb08d 100644
--- a/drivers/usb/host/ehci-hcd.c
+++ b/drivers/usb/host/ehci-hcd.c
@@ -245,7 +245,7 @@  static int ehci_td_buffer(struct qTD *td, void *buf, size_t sz)
 
 	idx = 0;
 	while (idx < QT_BUFFER_CNT) {
-		td->qt_buffer[idx] = cpu_to_hc32(addr);
+		td->qt_buffer[idx] = cpu_to_hc32(virt_to_phys((void *)addr));
 		td->qt_buffer_hi[idx] = 0;
 		next = (addr + EHCI_PAGE_SIZE) & ~(EHCI_PAGE_SIZE - 1);
 		delta = next - addr;
@@ -398,7 +398,7 @@  ehci_submit_async(struct usb_device *dev, unsigned long pipe, void *buffer,
 	 *   qh_overlay.qt_next ...... 13-10 H
 	 * - qh_overlay.qt_altnext
 	 */
-	qh->qh_link = cpu_to_hc32((unsigned long)&ctrl->qh_list | QH_LINK_TYPE_QH);
+	qh->qh_link = cpu_to_hc32(virt_to_phys(&ctrl->qh_list) | QH_LINK_TYPE_QH);
 	c = (dev->speed != USB_SPEED_HIGH) && !usb_pipeendpoint(pipe);
 	maxpacket = usb_maxpacket(dev, pipe);
 	endpt = QH_ENDPT1_RL(8) | QH_ENDPT1_C(c) |
@@ -415,7 +415,6 @@  ehci_submit_async(struct usb_device *dev, unsigned long pipe, void *buffer,
 	qh->qh_overlay.qt_altnext = cpu_to_hc32(QT_NEXT_TERMINATE);
 
 	tdp = &qh->qh_overlay.qt_next;
-
 	if (req != NULL) {
 		/*
 		 * Setup request qTD (3.5 in ehci-r10.pdf)
@@ -438,7 +437,7 @@  ehci_submit_async(struct usb_device *dev, unsigned long pipe, void *buffer,
 			goto fail;
 		}
 		/* Update previous qTD! */
-		*tdp = cpu_to_hc32((unsigned long)&qtd[qtd_counter]);
+		*tdp = cpu_to_hc32(virt_to_phys(&qtd[qtd_counter]));
 		tdp = &qtd[qtd_counter++].qt_next;
 		toggle = 1;
 	}
@@ -497,7 +496,7 @@  ehci_submit_async(struct usb_device *dev, unsigned long pipe, void *buffer,
 				goto fail;
 			}
 			/* Update previous qTD! */
-			*tdp = cpu_to_hc32((unsigned long)&qtd[qtd_counter]);
+			*tdp = cpu_to_hc32(virt_to_phys(&qtd[qtd_counter]));
 			tdp = &qtd[qtd_counter++].qt_next;
 			/*
 			 * Data toggle has to be adjusted since the qTD transfer
@@ -528,11 +527,11 @@  ehci_submit_async(struct usb_device *dev, unsigned long pipe, void *buffer,
 			QT_TOKEN_STATUS(QT_TOKEN_STATUS_ACTIVE);
 		qtd[qtd_counter].qt_token = cpu_to_hc32(token);
 		/* Update previous qTD! */
-		*tdp = cpu_to_hc32((unsigned long)&qtd[qtd_counter]);
+		*tdp = cpu_to_hc32(virt_to_phys(&qtd[qtd_counter]));
 		tdp = &qtd[qtd_counter++].qt_next;
 	}
 
-	ctrl->qh_list.qh_link = cpu_to_hc32((unsigned long)qh | QH_LINK_TYPE_QH);
+	ctrl->qh_list.qh_link = cpu_to_hc32(virt_to_phys(qh) | QH_LINK_TYPE_QH);
 
 	/* Flush dcache */
 	flush_dcache_range((unsigned long)&ctrl->qh_list,
@@ -542,7 +541,7 @@  ehci_submit_async(struct usb_device *dev, unsigned long pipe, void *buffer,
 			   ALIGN_END_ADDR(struct qTD, qtd, qtd_count));
 
 	/* Set async. queue head pointer. */
-	ehci_writel(&ctrl->hcor->or_asynclistaddr, (unsigned long)&ctrl->qh_list);
+	ehci_writel(&ctrl->hcor->or_asynclistaddr, virt_to_phys(&ctrl->qh_list));
 
 	usbsts = ehci_readl(&ctrl->hcor->or_usbsts);
 	ehci_writel(&ctrl->hcor->or_usbsts, (usbsts & 0x3f));
@@ -989,7 +988,7 @@  static int ehci_common_init(struct ehci_ctrl *ctrl, uint tweaks)
 
 	/* Set head of reclaim list */
 	memset(qh_list, 0, sizeof(*qh_list));
-	qh_list->qh_link = cpu_to_hc32((unsigned long)qh_list | QH_LINK_TYPE_QH);
+	qh_list->qh_link = cpu_to_hc32(virt_to_phys(qh_list) | QH_LINK_TYPE_QH);
 	qh_list->qh_endpt1 = cpu_to_hc32(QH_ENDPT1_H(1) |
 						QH_ENDPT1_EPS(USB_SPEED_HIGH));
 	qh_list->qh_overlay.qt_next = cpu_to_hc32(QT_NEXT_TERMINATE);
@@ -1001,7 +1000,7 @@  static int ehci_common_init(struct ehci_ctrl *ctrl, uint tweaks)
 			   ALIGN_END_ADDR(struct QH, qh_list, 1));
 
 	/* Set async. queue head pointer. */
-	ehci_writel(&ctrl->hcor->or_asynclistaddr, (unsigned long)qh_list);
+	ehci_writel(&ctrl->hcor->or_asynclistaddr, virt_to_phys(qh_list));
 
 	/*
 	 * Set up periodic list