Re: dwc3 initiated xhci probe problem in arm64 4.4 kernel due to DMA setup

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

 



On 04/15/2016 03:55 PM, Felipe Balbi wrote:
> Grygorii Strashko <grygorii.strashko@xxxxxx> writes:
>> On 04/15/2016 02:31 PM, Felipe Balbi wrote:
>>> Catalin Marinas <catalin.marinas@xxxxxxx> writes:
>>>> On Fri, Apr 15, 2016 at 01:30:01PM +0300, Felipe Balbi wrote:
>>>>> Catalin Marinas <catalin.marinas@xxxxxxx> writes:
>>>>>> On Fri, Apr 15, 2016 at 11:01:08AM +0100, Catalin Marinas wrote:
>>>>>>> On Fri, Apr 15, 2016 at 12:49:15PM +0300, Felipe Balbi wrote:
>>>>>>>> Catalin Marinas <catalin.marinas@xxxxxxx> writes:
>>>>>>>>> On Thu, Apr 14, 2016 at 12:46:47PM +0000, David Fisher wrote:
>>>>>>>>>> dwc3 is in dual-role, with "synopsys,dwc3" specified in DT.
>>>>>>>>>>
>>>>>>>>>> When xhci is probed, initiated from dwc3/host.c (not DT), we get :
>>>>>>>>>> xhci-hcd: probe of xhci-hcd.7.auto failed with error -5
>>>>>>>>>> This -EIO error originated from inside dma_set_mask() down in include/asm-generic/dma-mapping-common.h
>>>>>>>>>>
>>>>>>>>>> If "generic-xhci" is specified in DT instead, it probes fine as a host-only dwc3
>>>>>>>>>> The difference between DT initiated probe and dwc3 initiated probe is that
>>>>>>>>>> when DT initiated probe gets to dma_supported, dma_supported is
>>>>>>>>>> implemented by swiotlb_dma_supported (previously set up by a DT call to arch_dma_setup_ops).
>>>>>>>>>> Whereas when dwc3 initiated xhci probe gets to dma_supported, arch_dma_setup_ops has not been called
>>>>>>>>>> and dma_supported is only implemented by __dummy_dma_supported, returning 0.
>>>>>>>>>>
>>>>>>>>>> Bisecting finds the "bad" commit as
>>>>>>>>>> 1dccb598df549d892b6450c261da54cdd7af44b4  (inbetween 4.4-rc1 and 4.4-rc2)
>>>>>>>>>> --- a/arch/arm64/include/asm/dma-mapping.h
>>>>>>>>>> --- a/arch/arm64/mm/dma-mapping.c
>>>>>>>>>>
>>>>>>>>>> Previous to this commit, dma_ops = &swiotlb_dma_ops was done in arm64_dma_init
>>>>>>>>>> After this commit, the assignment is only done in arch_dma_setup_ops.
>>>>>>>>>
>>>>>>>>> This restriction was added on purpose and the arm64 __generic_dma_ops()
>>>>>>>>> now has a comment:
>>>>>>>>>
>>>>>>>>> 	/*
>>>>>>>>> 	 * We expect no ISA devices, and all other DMA masters are expected to
>>>>>>>>> 	 * have someone call arch_setup_dma_ops at device creation time.
>>>>>>>>> 	 */
>>>>>>>>
>>>>>>>> how ?
>>>>>>>
>>>>>>> Usually by calling arch_setup_dma_ops().
>>>>>>
>>>>>> Or of_dma_configure(), I forgot to mention this (see the
>>>>>> pci_dma_configure() function as an example).
>>>>>
>>>>> the device is manually created, there's not OF/DT for it ;-)
>>>>
>>>> As for PCI, the created device doesn't have a node but the bridge does.
>>>> Something like below, completely untested:
>>>>
>>>> diff --git a/drivers/usb/dwc3/host.c b/drivers/usb/dwc3/host.c
>>>> index c679f63783ae..96d8babd7f23 100644
>>>> --- a/drivers/usb/dwc3/host.c
>>>> +++ b/drivers/usb/dwc3/host.c
>>>> @@ -32,7 +32,10 @@ int dwc3_host_init(struct dwc3 *dwc)
>>>>    		return -ENOMEM;
>>>>    	}
>>>>    
>>>> -	dma_set_coherent_mask(&xhci->dev, dwc->dev->coherent_dma_mask);
>>>> +	if (IS_ENABLED(CONFIG_OF) && dwc->dev->of_node)
>>>> +		of_dma_configure(&xhci->dev, dwc->dev->of_node);
>>>> +	else
>> {
>>>> +		dma_set_coherent_mask(&xhci->dev, dwc->dev->coherent_dma_mask);
>>
>> 	 xhci->dev.dma_mask      = dwc->dev->dma_mask;
>>           xhci->dev.dma_parms     = dwc->dev->dma_parms;
>> }
>>
>>>
>>> assuming this works fine for all users, I don't have an issue with
>>> it. Grygorii has just been working on DMA setup for k2 and dwc3, so I
>>> want to make sure this won't regress those devices.
>>>
>>
>> And this is the same approach I've proposed here:
>> https://lkml.org/lkml/2016/3/31/609
>>
>> :)
>>
>> So, final change could be:
>>
>> ---
>>  From c68225e97e8c9505aca4ceab19a0d8e4dde31b73 Mon Sep 17 00:00:00 2001
>> From: Grygorii Strashko <grygorii.strashko@xxxxxx>
>> Date: Thu, 31 Mar 2016 19:40:52 +0300
>> Subject: [PATCH] usb: dwc3: host: inherit dma configuration from parent dev
>>
>> Now not all DMA paremters configured properly for "xhci-hcd" platform
>> device which is created manually. For example: dma_pfn_offset, dam_ops
>> and iommu configuration will not corresponds "dwc3" devices
>> configuration. As result, this will cause problems like wrong DMA
>> addresses translation on platforms with LPAE enabled like Keystone 2.
>>
>> When platform is using DT boot mode the DMA configuration will be
>> parsed and applied from DT, so, to fix this issue, reuse
>> of_dma_configure() API and retrieve DMA configuartion for "xhci-hcd"
>> from DWC3 device node.
>>
>> Signed-off-by: Grygorii Strashko <grygorii.strashko@xxxxxx>
>> ---
>>   drivers/usb/dwc3/host.c | 15 ++++++++++-----
>>   1 file changed, 10 insertions(+), 5 deletions(-)
>>
>> diff --git a/drivers/usb/dwc3/host.c b/drivers/usb/dwc3/host.c
>> index c679f63..93c8ef9 100644
>> --- a/drivers/usb/dwc3/host.c
>> +++ b/drivers/usb/dwc3/host.c
>> @@ -17,6 +17,7 @@
>>   
>>   #include <linux/platform_device.h>
>>   #include <linux/usb/xhci_pdriver.h>
>> +#include <linux/of_device.h>
>>   
>>   #include "core.h"
>>   
>> @@ -32,12 +33,7 @@ int dwc3_host_init(struct dwc3 *dwc)
>>   		return -ENOMEM;
>>   	}
>>   
>> -	dma_set_coherent_mask(&xhci->dev, dwc->dev->coherent_dma_mask);
>> -
>>   	xhci->dev.parent	= dwc->dev;
>> -	xhci->dev.dma_mask	= dwc->dev->dma_mask;
>> -	xhci->dev.dma_parms	= dwc->dev->dma_parms;
>> -
>>   	dwc->xhci = xhci;
>>   
>>   	ret = platform_device_add_resources(xhci, dwc->xhci_resources,
>> @@ -62,6 +58,15 @@ int dwc3_host_init(struct dwc3 *dwc)
>>   	phy_create_lookup(dwc->usb3_generic_phy, "usb3-phy",
>>   			  dev_name(&xhci->dev));
>>   
>> +	if (IS_ENABLED(CONFIG_OF) && dwc->dev->of_node) {
>> +		of_dma_configure(&xhci->dev, dwc->dev->of_node);
>> +	} else {
>> +		dma_set_coherent_mask(&xhci->dev, dwc->dev->coherent_dma_mask);
>> +
>> +		xhci->dev.dma_mask	= dwc->dev->dma_mask;
>> +		xhci->dev.dma_parms	= dwc->dev->dma_parms;
>> +	}
>> +
>>   	ret = platform_device_add(xhci);
>>   	if (ret) {
>>   		dev_err(dwc->dev, "failed to register xHCI device\n");
>> -- 
>> 2.8.1
> 
> David, does this work for your setup ?
> 

Felipe, Seems the problem might be deeper than on first look :(

Lets see what grep says below. Even if we descope all SoC's drivers,
there still will be few USB core components which manipulate with DMA parameters:

---
./drivers/usb/core/hcd.c:	hcd->self.uses_dma = (dev->dma_mask != NULL);
usb_create_shared_hcd()
	hcd->self.uses_dma = (dev->dma_mask != NULL);

---
./drivers/usb/core/usb.c:	dev->dev.dma_mask = bus->controller->dma_mask;
usb_alloc_dev()
	dev->dev.dma_mask = bus->controller->dma_mask;

---
./drivers/usb/core/message.c:		intf->dev.dma_mask = dev->dev.dma_mask;
usb_set_configuration()
	intf->dev.dma_mask = dev->dev.dma_mask;

^ why it is here is total mystery :(

---
./drivers/usb/dwc3/core.c:		dev->dma_mask = dev->parent->dma_mask;

---
./drivers/usb/dwc2/hcd.c:	/* Check if the bus driver or platform code has setup a dma_mask */
dwc2_hcd_init()
	dma_set_mask(hsotg->dev, DMA_BIT_MASK(32)) < 0)

---
./drivers/usb/host/xhci.c:
xhci_gen_setup()
	!dma_set_mask(dev, DMA_BIT_MASK(64)
./drivers/usb/host/xhci-plat.c:	if (WARN_ON(!pdev->dev.dma_mask))

---
./drivers/usb/musb/musb_core.c:	if (use_dma && dev->dma_mask) {

---
./drivers/usb/storage/scsiglue.c:	if (!us->pusb_dev->bus->controller->dma_mask)

It is big secret as for me (I'm USB noob:) which device is used for DMA transfers and when :(


-------------------------------------------------------------------------------------
grep -Ir -w dma_mask ./drivers/usb/*
./drivers/usb/chipidea/core.c:	pdev->dev.dma_mask = dev->dma_mask;
./drivers/usb/core/hcd.c:	hcd->self.uses_dma = (dev->dma_mask != NULL);
./drivers/usb/core/usb.c:	dev->dev.dma_mask = bus->controller->dma_mask;
./drivers/usb/core/usb.c:	if (controller->dma_mask) {
./drivers/usb/core/usb.c:	if (controller->dma_mask) {
./drivers/usb/core/usb.c:	if (controller->dma_mask) {
./drivers/usb/core/usb.c:			|| !controller->dma_mask)
./drivers/usb/core/usb.c:			|| !controller->dma_mask)
./drivers/usb/core/usb.c:			|| !controller->dma_mask)
./drivers/usb/core/buffer.c:	    (!hcd->self.controller->dma_mask &&
./drivers/usb/core/buffer.c:	    (!bus->controller->dma_mask &&
./drivers/usb/core/buffer.c:	    (!bus->controller->dma_mask &&
./drivers/usb/core/message.c:		intf->dev.dma_mask = dev->dev.dma_mask;
./drivers/usb/dwc2/hcd.c:	/* Check if the bus driver or platform code has setup a dma_mask */
./drivers/usb/dwc2/hcd.c:	    hsotg->dev->dma_mask == NULL) {
./drivers/usb/dwc2/hcd.c:			 "dma_mask not set, disabling DMA\n");
./drivers/usb/dwc2/platform.c:	if (!dev->dev.dma_mask)
./drivers/usb/dwc2/platform.c:		dev->dev.dma_mask = &dev->dev.coherent_dma_mask;
./drivers/usb/dwc3/dwc3-exynos.c:	 * Right now device-tree probed devices don't get dma_mask set.
./drivers/usb/dwc3/host.c:		xhci->dev.dma_mask	= dwc->dev->dma_mask;
./drivers/usb/dwc3/core.c:	if (!dev->dma_mask) {
./drivers/usb/dwc3/core.c:		dev->dma_mask = dev->parent->dma_mask;
./drivers/usb/gadget/udc/fotg210-udc.c:	fotg210->gadget.dev.dma_mask = pdev->dev.dma_mask;
./drivers/usb/gadget/udc/lpc32xx_udc.c:	pdev->dev.dma_mask = &lpc32xx_usbd_dmamask;
./drivers/usb/gadget/udc/bdc/bdc_pci.c:	bdc->dev.dma_mask = pci->dev.dma_mask;
./drivers/usb/gadget/udc/pxa25x_udc.h:	u64					dma_mask;
./drivers/usb/host/isp116x-hcd.c:	if (pdev->dev.dma_mask) {
./drivers/usb/host/ehci-grlib.c:	/* usb_create_hcd requires dma_mask != NULL */
./drivers/usb/host/ehci-grlib.c:	op->dev.dma_mask = &op->dev.coherent_dma_mask;
./drivers/usb/host/ehci-orion.c:	 * Right now device-tree probed devices don't get dma_mask
./drivers/usb/host/ohci-at91.c:	/* Right now device-tree probed devices don't get dma_mask set.
./drivers/usb/host/uhci-grlib.c:	/* usb_create_hcd requires dma_mask != NULL */
./drivers/usb/host/uhci-grlib.c:	op->dev.dma_mask = &op->dev.coherent_dma_mask;
./drivers/usb/host/isp1362-hcd.c:	if (pdev->dev.dma_mask) {
./drivers/usb/host/ehci-spear.c:	 * Right now device-tree probed devices don't get dma_mask set.
./drivers/usb/host/ehci-hcd.c:	 * NOTE:  the dma mask is visible through dev->dma_mask, so
./drivers/usb/host/uhci-platform.c:	 * Right now device-tree probed devices don't get dma_mask set.
./drivers/usb/host/ohci-spear.c:	 * Right now device-tree probed devices don't get dma_mask set.
./drivers/usb/host/bcma-hcd.c:	hci_dev->dev.dma_mask = &hci_dev->dev.coherent_dma_mask;
./drivers/usb/host/oxu210hp-hcd.c:	hcd->self.controller->dma_mask = NULL;
./drivers/usb/host/oxu210hp-hcd.c:	 * NOTE:  the dma mask is visible through dev->dma_mask, so
./drivers/usb/host/ehci-ps3.c:	dev->core.dma_mask = &dummy_mask; /* FIXME: for improper usb code */
./drivers/usb/host/ohci-ps3.c:	dev->core.dma_mask = &dummy_mask; /* FIXME: for improper usb code */
./drivers/usb/host/xhci.c:	/* Set dma_mask and coherent_dma_mask to 64-bits,
./drivers/usb/host/ohci-exynos.c:	 * Right now device-tree probed devices don't get dma_mask set.
./drivers/usb/host/ohci-omap3.c:	 * Right now device-tree probed devices don't get dma_mask set.
./drivers/usb/host/ehci-omap.c:	 * Right now device-tree probed devices don't get dma_mask set.
./drivers/usb/host/ssb-hcd.c:	hci_dev->dev.dma_mask = &hci_dev->dev.coherent_dma_mask;
./drivers/usb/host/xhci-plat.c:	if (WARN_ON(!pdev->dev.dma_mask))
./drivers/usb/host/xhci-plat.c:		/* Platform did not initialize dma_mask */
./drivers/usb/host/u132-hcd.c:	if (pdev->dev.dma_mask)
./drivers/usb/host/ehci-tegra.c:	/* Right now device-tree probed devices don't get dma_mask set.
./drivers/usb/host/r8a66597-hcd.c:	if (pdev->dev.dma_mask) {
./drivers/usb/host/ohci-pxa27x.c:	/* Right now device-tree probed devices don't get dma_mask set.
./drivers/usb/host/ehci-exynos.c:	 * Right now device-tree probed devices don't get dma_mask set.
./drivers/usb/host/fotg210-hcd.c:	 * NOTE:  the dma mask is visible through dev->dma_mask, so
./drivers/usb/host/fsl-mph-dr-of.c:	if (!pdev->dev.dma_mask)
./drivers/usb/host/fsl-mph-dr-of.c:		pdev->dev.dma_mask = &ofdev->dev.coherent_dma_mask;
./drivers/usb/host/xhci-mtk.c:	/* Initialize dma_mask and coherent_dma_mask to 32-bits */
./drivers/usb/host/xhci-mtk.c:	if (!dev->dma_mask)
./drivers/usb/host/xhci-mtk.c:		dev->dma_mask = &dev->coherent_dma_mask;
./drivers/usb/host/ehci-atmel.c:	/* Right now device-tree probed devices don't get dma_mask set.
./drivers/usb/host/sl811-hcd.c:	if (dev->dev.dma_mask) {
./drivers/usb/isp1760/isp1760-core.c:	dev->dma_mask = NULL;
./drivers/usb/isp1760/isp1760-if.c:	dev->dev.dma_mask = NULL;
./drivers/usb/misc/ftdi-elan.c:	ftdi->platform_dev.dev.dma_mask = NULL;
./drivers/usb/musb/musb_core.c:	if (use_dma && dev->dma_mask) {
./drivers/usb/musb/davinci.c:	.dma_mask	= DMA_BIT_MASK(32),
./drivers/usb/musb/omap2430.c:	musb->dev.dma_mask		= &omap2430_dmamask;
./drivers/usb/musb/da8xx.c:	.dma_mask	= DMA_BIT_MASK(32),
./drivers/usb/musb/tusb6010.c:	.dma_mask	= DMA_BIT_MASK(32),
./drivers/usb/musb/blackfin.c:	musb->dev.dma_mask		= &bfin_dmamask;
./drivers/usb/musb/musb_dsps.c:	musb->dev.dma_mask		= &musb_dmamask;
./drivers/usb/musb/am35x.c:	.dma_mask	= DMA_BIT_MASK(32),
./drivers/usb/musb/ux500.c:	musb->dev.dma_mask		= &pdev->dev.coherent_dma_mask;
./drivers/usb/storage/scsiglue.c:	 * They indicate this by setting their dma_mask to NULL.  For
./drivers/usb/storage/scsiglue.c:	if (!us->pusb_dev->bus->controller->dma_mask)


-- 
regards,
-grygorii
--
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