diff mbox series

[U-Boot,RFC] usb: ehci: do not invalidate a NULL buffer

Message ID 20171117142836.3456-1-dirk.behme@de.bosch.com
State Accepted
Commit b3cbcd902db7019410dfe3729a660abcb1f03ffb
Delegated to: Marek Vasut
Headers show
Series [U-Boot,RFC] usb: ehci: do not invalidate a NULL buffer | expand

Commit Message

Dirk Behme Nov. 17, 2017, 2:28 p.m. UTC
Its a valid use case to call ehci_submit_async() with a NULL buffer
with length 0. E.g. from usb_set_configuration().

As invalidate_dcache_range() isn't able to judge if the address
NULL is valid or not (depending on the SoC hardware configuration it
might be valid) do the check in ehci_submit_async() as here we know
that we don't have to invalidate such a buffer.

Signed-off-by: Dirk Behme <dirk.behme@de.bosch.com>

---
Notes:

This was found on an older vendor specific U-Boot on an ARMv8 SoC
with a MMU configuration where address 0x00000000 is invalid.

The callstack I've seen is

usb_set_configuration(), calls
 -> usb_control_msg() with *data == NULL and size == 0
  -> submit_control_msg()
   -> _ehci_submit_control_msg()
    -> ehci_submit_async()

ehci_submit_async() called  __asm_invalidate_dcache_range() from
arch/arm/cpu/armv8/cache.S, then. Resulting in an exception trying
to use address 0 in x0 (dc ivac, x0).

I'm slightly unsure why this hasn't been catched or complained about
previously, already. Maybe I missed anything while working with an older
vendor U-Boot? Sorry in this case.

Best regards

Dirk
---
 drivers/usb/host/ehci-hcd.c | 5 +++--
 1 file changed, 3 insertions(+), 2 deletions(-)

Comments

Marek Vasut Nov. 17, 2017, 3:04 p.m. UTC | #1
On 11/17/2017 03:28 PM, Dirk Behme wrote:
> Its a valid use case to call ehci_submit_async() with a NULL buffer
> with length 0. E.g. from usb_set_configuration().
> 
> As invalidate_dcache_range() isn't able to judge if the address
> NULL is valid or not (depending on the SoC hardware configuration it
> might be valid) do the check in ehci_submit_async() as here we know
> that we don't have to invalidate such a buffer.
> 
> Signed-off-by: Dirk Behme <dirk.behme@de.bosch.com>

Looks OK, what about the other cache ops in EHCI, are they also affected?

> ---
> Notes:
> 
> This was found on an older vendor specific U-Boot on an ARMv8 SoC
> with a MMU configuration where address 0x00000000 is invalid.
> 
> The callstack I've seen is
> 
> usb_set_configuration(), calls
>  -> usb_control_msg() with *data == NULL and size == 0
>   -> submit_control_msg()
>    -> _ehci_submit_control_msg()
>     -> ehci_submit_async()
> 
> ehci_submit_async() called  __asm_invalidate_dcache_range() from
> arch/arm/cpu/armv8/cache.S, then. Resulting in an exception trying
> to use address 0 in x0 (dc ivac, x0).
> 
> I'm slightly unsure why this hasn't been catched or complained about
> previously, already. Maybe I missed anything while working with an older
> vendor U-Boot? Sorry in this case.
> 
> Best regards
> 
> Dirk
> ---
>  drivers/usb/host/ehci-hcd.c | 5 +++--
>  1 file changed, 3 insertions(+), 2 deletions(-)
> 
> diff --git a/drivers/usb/host/ehci-hcd.c b/drivers/usb/host/ehci-hcd.c
> index be3e842dcc..32c661b37e 100644
> --- a/drivers/usb/host/ehci-hcd.c
> +++ b/drivers/usb/host/ehci-hcd.c
> @@ -595,8 +595,9 @@ ehci_submit_async(struct usb_device *dev, unsigned long pipe, void *buffer,
>  	 * dangerous operation, it's responsibility of the calling
>  	 * code to make sure enough space is reserved.
>  	 */
> -	invalidate_dcache_range((unsigned long)buffer,
> -		ALIGN((unsigned long)buffer + length, ARCH_DMA_MINALIGN));
> +	if (buffer != NULL && length > 0)
> +		invalidate_dcache_range((unsigned long)buffer,
> +			ALIGN((unsigned long)buffer + length, ARCH_DMA_MINALIGN));
>  
>  	/* Check that the TD processing happened */
>  	if (QT_TOKEN_GET_STATUS(token) & QT_TOKEN_STATUS_ACTIVE)
>
Behme Dirk (CM/ESO2) Nov. 21, 2017, 6:30 a.m. UTC | #2
On 17.11.2017 16:04, Marek Vasut wrote:
> On 11/17/2017 03:28 PM, Dirk Behme wrote:
>> Its a valid use case to call ehci_submit_async() with a NULL buffer
>> with length 0. E.g. from usb_set_configuration().
>>
>> As invalidate_dcache_range() isn't able to judge if the address
>> NULL is valid or not (depending on the SoC hardware configuration it
>> might be valid) do the check in ehci_submit_async() as here we know
>> that we don't have to invalidate such a buffer.
>>
>> Signed-off-by: Dirk Behme <dirk.behme@de.bosch.com>
> 
> Looks OK, 


Ok, thanks, I'll drop the RFC, then.


> what about the other cache ops in EHCI, are they also affected?


This was found based on a MMU configuration excluding address 
0x00000000. Fixing this one location made a usb start and reading from 
an USB stick work.

So either only this location is affected, or above use case doesn't 
cover all relevant path. In latter case I don't have enough USB 
knowledge to evaluate all path by review.

Best regards

Dirk


>> ---
>> Notes:
>>
>> This was found on an older vendor specific U-Boot on an ARMv8 SoC
>> with a MMU configuration where address 0x00000000 is invalid.
>>
>> The callstack I've seen is
>>
>> usb_set_configuration(), calls
>>   -> usb_control_msg() with *data == NULL and size == 0
>>    -> submit_control_msg()
>>     -> _ehci_submit_control_msg()
>>      -> ehci_submit_async()
>>
>> ehci_submit_async() called  __asm_invalidate_dcache_range() from
>> arch/arm/cpu/armv8/cache.S, then. Resulting in an exception trying
>> to use address 0 in x0 (dc ivac, x0).
>>
>> I'm slightly unsure why this hasn't been catched or complained about
>> previously, already. Maybe I missed anything while working with an older
>> vendor U-Boot? Sorry in this case.
>>
>> Best regards
>>
>> Dirk
>> ---
>>   drivers/usb/host/ehci-hcd.c | 5 +++--
>>   1 file changed, 3 insertions(+), 2 deletions(-)
>>
>> diff --git a/drivers/usb/host/ehci-hcd.c b/drivers/usb/host/ehci-hcd.c
>> index be3e842dcc..32c661b37e 100644
>> --- a/drivers/usb/host/ehci-hcd.c
>> +++ b/drivers/usb/host/ehci-hcd.c
>> @@ -595,8 +595,9 @@ ehci_submit_async(struct usb_device *dev, unsigned long pipe, void *buffer,
>>   	 * dangerous operation, it's responsibility of the calling
>>   	 * code to make sure enough space is reserved.
>>   	 */
>> -	invalidate_dcache_range((unsigned long)buffer,
>> -		ALIGN((unsigned long)buffer + length, ARCH_DMA_MINALIGN));
>> +	if (buffer != NULL && length > 0)
>> +		invalidate_dcache_range((unsigned long)buffer,
>> +			ALIGN((unsigned long)buffer + length, ARCH_DMA_MINALIGN));
>>   
>>   	/* Check that the TD processing happened */
>>   	if (QT_TOKEN_GET_STATUS(token) & QT_TOKEN_STATUS_ACTIVE)
>>
Marek Vasut Nov. 21, 2017, 11:28 a.m. UTC | #3
On 11/21/2017 07:30 AM, Dirk Behme wrote:
> On 17.11.2017 16:04, Marek Vasut wrote:
>> On 11/17/2017 03:28 PM, Dirk Behme wrote:
>>> Its a valid use case to call ehci_submit_async() with a NULL buffer
>>> with length 0. E.g. from usb_set_configuration().
>>>
>>> As invalidate_dcache_range() isn't able to judge if the address
>>> NULL is valid or not (depending on the SoC hardware configuration it
>>> might be valid) do the check in ehci_submit_async() as here we know
>>> that we don't have to invalidate such a buffer.
>>>
>>> Signed-off-by: Dirk Behme <dirk.behme@de.bosch.com>
>>
>> Looks OK, 
> 
> 
> Ok, thanks, I'll drop the RFC, then.
> 
> 
>> what about the other cache ops in EHCI, are they also affected?
> 
> 
> This was found based on a MMU configuration excluding address
> 0x00000000. Fixing this one location made a usb start and reading from
> an USB stick work.
> 
> So either only this location is affected, or above use case doesn't
> cover all relevant path. In latter case I don't have enough USB
> knowledge to evaluate all path by review.

Well, I skimmed through the rest of the function and this seems to be
the only spot where it could be problematic if length == 0 , so this is
the correct fix.

Applied, thanks.

> Best regards
> 
> Dirk
> 
> 
>>> ---
>>> Notes:
>>>
>>> This was found on an older vendor specific U-Boot on an ARMv8 SoC
>>> with a MMU configuration where address 0x00000000 is invalid.
>>>
>>> The callstack I've seen is
>>>
>>> usb_set_configuration(), calls
>>>   -> usb_control_msg() with *data == NULL and size == 0
>>>    -> submit_control_msg()
>>>     -> _ehci_submit_control_msg()
>>>      -> ehci_submit_async()
>>>
>>> ehci_submit_async() called  __asm_invalidate_dcache_range() from
>>> arch/arm/cpu/armv8/cache.S, then. Resulting in an exception trying
>>> to use address 0 in x0 (dc ivac, x0).
>>>
>>> I'm slightly unsure why this hasn't been catched or complained about
>>> previously, already. Maybe I missed anything while working with an older
>>> vendor U-Boot? Sorry in this case.
>>>
>>> Best regards
>>>
>>> Dirk
>>> ---
>>>   drivers/usb/host/ehci-hcd.c | 5 +++--
>>>   1 file changed, 3 insertions(+), 2 deletions(-)
>>>
>>> diff --git a/drivers/usb/host/ehci-hcd.c b/drivers/usb/host/ehci-hcd.c
>>> index be3e842dcc..32c661b37e 100644
>>> --- a/drivers/usb/host/ehci-hcd.c
>>> +++ b/drivers/usb/host/ehci-hcd.c
>>> @@ -595,8 +595,9 @@ ehci_submit_async(struct usb_device *dev,
>>> unsigned long pipe, void *buffer,
>>>        * dangerous operation, it's responsibility of the calling
>>>        * code to make sure enough space is reserved.
>>>        */
>>> -    invalidate_dcache_range((unsigned long)buffer,
>>> -        ALIGN((unsigned long)buffer + length, ARCH_DMA_MINALIGN));
>>> +    if (buffer != NULL && length > 0)
>>> +        invalidate_dcache_range((unsigned long)buffer,
>>> +            ALIGN((unsigned long)buffer + length, ARCH_DMA_MINALIGN));
>>>         /* Check that the TD processing happened */
>>>       if (QT_TOKEN_GET_STATUS(token) & QT_TOKEN_STATUS_ACTIVE)
>>>
diff mbox series

Patch

diff --git a/drivers/usb/host/ehci-hcd.c b/drivers/usb/host/ehci-hcd.c
index be3e842dcc..32c661b37e 100644
--- a/drivers/usb/host/ehci-hcd.c
+++ b/drivers/usb/host/ehci-hcd.c
@@ -595,8 +595,9 @@  ehci_submit_async(struct usb_device *dev, unsigned long pipe, void *buffer,
 	 * dangerous operation, it's responsibility of the calling
 	 * code to make sure enough space is reserved.
 	 */
-	invalidate_dcache_range((unsigned long)buffer,
-		ALIGN((unsigned long)buffer + length, ARCH_DMA_MINALIGN));
+	if (buffer != NULL && length > 0)
+		invalidate_dcache_range((unsigned long)buffer,
+			ALIGN((unsigned long)buffer + length, ARCH_DMA_MINALIGN));
 
 	/* Check that the TD processing happened */
 	if (QT_TOKEN_GET_STATUS(token) & QT_TOKEN_STATUS_ACTIVE)