diff mbox

[U-Boot,v2] usbh/ehci: Increase timeout for enumeration

Message ID bbba7de214710423270361c6c99bbb39d5ef15c2.1354870373.git.vipin.kumar@st.com
State Superseded
Delegated to: Marek Vasut
Headers show

Commit Message

Vipin Kumar Dec. 7, 2012, 8:58 a.m. UTC
The current logic reads the port status just once after usb_hub_power_on and
expects the portstatus and portchange to report the connection status
immediately and correctly.

Few pen drives are not able to report both of them immediately ie. those pens
report the connection change but not the connected state after the first read.
This opportunity once lost is gone for ever because the u-boot, unlike linux or
any other OS, works in polling mode.

This patch modifies the logic to read the port status continuously until the
portstatus and portchange both report a connection change as well as a connected
state or no connection change and no connection. This logic is placed in a
timeout of 10 sec. At the end of it, the pen drive would have either reported a
ONE or a ZERO in bit 1 of portstatus as well as portchange.

It enhances the set of pen drives which can eventually be detected by u-boot

Signed-off-by: Vipin Kumar <vipin.kumar@st.com>
---
Hello Marek, Igor,

I found another way to handle it. Please let me know if it is OK from the USB
stack poit of view. The fact is that a few pens do not report a connected status
in portstatus while they report a connection change in portchange after a
usb_hub_power_on.

In this patch, I have tried to compare the connection bit from portstatus and
portchange for a timeout of 10 seconds. The situation is asumed to be stable
once both of them report the same. This seems to have increased the set of pens
supported by u-boot without any apparent side effect

Please let me know if this is OK from your side

Regards
Vipin

 common/usb_hub.c | 25 ++++++++++++++++++++-----
 1 file changed, 20 insertions(+), 5 deletions(-)

Comments

Igor Grinberg Dec. 7, 2012, 10:03 a.m. UTC | #1
On 12/07/12 10:58, Vipin Kumar wrote:
> The current logic reads the port status just once after usb_hub_power_on and
> expects the portstatus and portchange to report the connection status
> immediately and correctly.
> 
> Few pen drives are not able to report both of them immediately ie. those pens
> report the connection change but not the connected state after the first read.
> This opportunity once lost is gone for ever because the u-boot, unlike linux or
> any other OS, works in polling mode.
> 
> This patch modifies the logic to read the port status continuously until the
> portstatus and portchange both report a connection change as well as a connected
> state or no connection change and no connection. This logic is placed in a
> timeout of 10 sec. At the end of it, the pen drive would have either reported a
> ONE or a ZERO in bit 1 of portstatus as well as portchange.
> 
> It enhances the set of pen drives which can eventually be detected by u-boot
> 
> Signed-off-by: Vipin Kumar <vipin.kumar@st.com>
> ---
> Hello Marek, Igor,
> 
> I found another way to handle it. Please let me know if it is OK from the USB
> stack poit of view. The fact is that a few pens do not report a connected status
> in portstatus while they report a connection change in portchange after a
> usb_hub_power_on.
> 
> In this patch, I have tried to compare the connection bit from portstatus and
> portchange for a timeout of 10 seconds. The situation is asumed to be stable
> once both of them report the same. This seems to have increased the set of pens
> supported by u-boot without any apparent side effect
> 
> Please let me know if this is OK from your side

Basically, this one looks fine, although I have two minor concerns below.

> 
> Regards
> Vipin
> 
>  common/usb_hub.c | 25 ++++++++++++++++++++-----
>  1 file changed, 20 insertions(+), 5 deletions(-)
> 
> diff --git a/common/usb_hub.c b/common/usb_hub.c
> index e4a1201..3a66b0e 100644
> --- a/common/usb_hub.c
> +++ b/common/usb_hub.c
> @@ -396,14 +396,29 @@ static int usb_hub_configure(struct usb_device *dev)
>  	for (i = 0; i < dev->maxchild; i++) {
>  		ALLOC_CACHE_ALIGN_BUFFER(struct usb_port_status, portsts, 1);
>  		unsigned short portstatus, portchange;
> +		int ret;
> +		ulong start = get_timer(0);
> +
> +		do {
> +			ret = usb_get_port_status(dev, i + 1, portsts);
> +			if (ret < 0) {
> +				USB_HUB_PRINTF("get_port_status failed\n");
> +				break;
> +			}
> +
> +			portstatus = le16_to_cpu(portsts->wPortStatus);
> +			portchange = le16_to_cpu(portsts->wPortChange);
> +
> +			if ((portchange & USB_PORT_STAT_C_CONNECTION) ==
> +				(portstatus & USB_PORT_STAT_CONNECTION))

I don't know if there is any corner case when the above check
will always fail and so it will always wait a maximal delay time.
Are those registers that identical, or can there be differences?

> +				break;
> +
> +			mdelay(100);
> +		} while (get_timer(start) < CONFIG_SYS_HZ * 10);

Is there any justification for the CONFIG_SYS_HZ * 10?
I would be much more fine with this patch if there were any
(even just test based * 2) reason for that number.

>  
> -		if (usb_get_port_status(dev, i + 1, portsts) < 0) {
> -			USB_HUB_PRINTF("get_port_status failed\n");
> +		if (ret < 0)
>  			continue;
> -		}
>  
> -		portstatus = le16_to_cpu(portsts->wPortStatus);
> -		portchange = le16_to_cpu(portsts->wPortChange);
>  		USB_HUB_PRINTF("Port %d Status %X Change %X\n",
>  				i + 1, portstatus, portchange);
>
Igor Grinberg Dec. 7, 2012, 10:18 a.m. UTC | #2
On 12/07/12 12:03, Igor Grinberg wrote:
> On 12/07/12 10:58, Vipin Kumar wrote:
>> The current logic reads the port status just once after usb_hub_power_on and
>> expects the portstatus and portchange to report the connection status
>> immediately and correctly.
>>
>> Few pen drives are not able to report both of them immediately ie. those pens
>> report the connection change but not the connected state after the first read.
>> This opportunity once lost is gone for ever because the u-boot, unlike linux or
>> any other OS, works in polling mode.
>>
>> This patch modifies the logic to read the port status continuously until the
>> portstatus and portchange both report a connection change as well as a connected
>> state or no connection change and no connection. This logic is placed in a
>> timeout of 10 sec. At the end of it, the pen drive would have either reported a
>> ONE or a ZERO in bit 1 of portstatus as well as portchange.
>>
>> It enhances the set of pen drives which can eventually be detected by u-boot
>>
>> Signed-off-by: Vipin Kumar <vipin.kumar@st.com>
>> ---
>> Hello Marek, Igor,
>>
>> I found another way to handle it. Please let me know if it is OK from the USB
>> stack poit of view. The fact is that a few pens do not report a connected status
>> in portstatus while they report a connection change in portchange after a
>> usb_hub_power_on.
>>
>> In this patch, I have tried to compare the connection bit from portstatus and
>> portchange for a timeout of 10 seconds. The situation is asumed to be stable
>> once both of them report the same. This seems to have increased the set of pens
>> supported by u-boot without any apparent side effect
>>
>> Please let me know if this is OK from your side
> 
> Basically, this one looks fine, although I have two minor concerns below.
> 
>>
>> Regards
>> Vipin
>>
>>  common/usb_hub.c | 25 ++++++++++++++++++++-----
>>  1 file changed, 20 insertions(+), 5 deletions(-)
>>
>> diff --git a/common/usb_hub.c b/common/usb_hub.c
>> index e4a1201..3a66b0e 100644
>> --- a/common/usb_hub.c
>> +++ b/common/usb_hub.c
>> @@ -396,14 +396,29 @@ static int usb_hub_configure(struct usb_device *dev)
>>  	for (i = 0; i < dev->maxchild; i++) {
>>  		ALLOC_CACHE_ALIGN_BUFFER(struct usb_port_status, portsts, 1);
>>  		unsigned short portstatus, portchange;
>> +		int ret;
>> +		ulong start = get_timer(0);
>> +
>> +		do {
>> +			ret = usb_get_port_status(dev, i + 1, portsts);
>> +			if (ret < 0) {
>> +				USB_HUB_PRINTF("get_port_status failed\n");
>> +				break;
>> +			}
>> +
>> +			portstatus = le16_to_cpu(portsts->wPortStatus);
>> +			portchange = le16_to_cpu(portsts->wPortChange);
>> +
>> +			if ((portchange & USB_PORT_STAT_C_CONNECTION) ==
>> +				(portstatus & USB_PORT_STAT_CONNECTION))
> 
> I don't know if there is any corner case when the above check
> will always fail and so it will always wait a maximal delay time.
> Are those registers that identical, or can there be differences?

Never mind, my mistake, USB_PORT_STAT_C_CONNECTION and USB_PORT_STAT_CONNECTION
are the same bit in the register.

> 
>> +				break;
>> +
>> +			mdelay(100);
>> +		} while (get_timer(start) < CONFIG_SYS_HZ * 10);
> 
> Is there any justification for the CONFIG_SYS_HZ * 10?
> I would be much more fine with this patch if there were any
> (even just test based * 2) reason for that number.

Once you address this one, feel free to add:
Acked-by: Igor Grinberg <grinberg@compulab.co.il>

> 
>>  
>> -		if (usb_get_port_status(dev, i + 1, portsts) < 0) {
>> -			USB_HUB_PRINTF("get_port_status failed\n");
>> +		if (ret < 0)
>>  			continue;
>> -		}
>>  
>> -		portstatus = le16_to_cpu(portsts->wPortStatus);
>> -		portchange = le16_to_cpu(portsts->wPortChange);
>>  		USB_HUB_PRINTF("Port %d Status %X Change %X\n",
>>  				i + 1, portstatus, portchange);
>>  
>
Vipin Kumar Dec. 7, 2012, 10:32 a.m. UTC | #3
On 12/7/2012 3:48 PM, Igor Grinberg wrote:
>
>
> On 12/07/12 12:03, Igor Grinberg wrote:
>> On 12/07/12 10:58, Vipin Kumar wrote:
>>> The current logic reads the port status just once after usb_hub_power_on and
>>> expects the portstatus and portchange to report the connection status
>>> immediately and correctly.
>>>
>>> Few pen drives are not able to report both of them immediately ie. those pens
>>> report the connection change but not the connected state after the first read.
>>> This opportunity once lost is gone for ever because the u-boot, unlike linux or
>>> any other OS, works in polling mode.
>>>
>>> This patch modifies the logic to read the port status continuously until the
>>> portstatus and portchange both report a connection change as well as a connected
>>> state or no connection change and no connection. This logic is placed in a
>>> timeout of 10 sec. At the end of it, the pen drive would have either reported a
>>> ONE or a ZERO in bit 1 of portstatus as well as portchange.
>>>
>>> It enhances the set of pen drives which can eventually be detected by u-boot
>>>
>>> Signed-off-by: Vipin Kumar<vipin.kumar@st.com>
>>> ---
>>> Hello Marek, Igor,
>>>
>>> I found another way to handle it. Please let me know if it is OK from the USB
>>> stack poit of view. The fact is that a few pens do not report a connected status
>>> in portstatus while they report a connection change in portchange after a
>>> usb_hub_power_on.
>>>
>>> In this patch, I have tried to compare the connection bit from portstatus and
>>> portchange for a timeout of 10 seconds. The situation is asumed to be stable
>>> once both of them report the same. This seems to have increased the set of pens
>>> supported by u-boot without any apparent side effect
>>>
>>> Please let me know if this is OK from your side
>>
>> Basically, this one looks fine, although I have two minor concerns below.
>>
>>>
>>> Regards
>>> Vipin
>>>
>>>   common/usb_hub.c | 25 ++++++++++++++++++++-----
>>>   1 file changed, 20 insertions(+), 5 deletions(-)
>>>
>>> diff --git a/common/usb_hub.c b/common/usb_hub.c
>>> index e4a1201..3a66b0e 100644
>>> --- a/common/usb_hub.c
>>> +++ b/common/usb_hub.c
>>> @@ -396,14 +396,29 @@ static int usb_hub_configure(struct usb_device *dev)
>>>   	for (i = 0; i<  dev->maxchild; i++) {
>>>   		ALLOC_CACHE_ALIGN_BUFFER(struct usb_port_status, portsts, 1);
>>>   		unsigned short portstatus, portchange;
>>> +		int ret;
>>> +		ulong start = get_timer(0);
>>> +
>>> +		do {
>>> +			ret = usb_get_port_status(dev, i + 1, portsts);
>>> +			if (ret<  0) {
>>> +				USB_HUB_PRINTF("get_port_status failed\n");
>>> +				break;
>>> +			}
>>> +
>>> +			portstatus = le16_to_cpu(portsts->wPortStatus);
>>> +			portchange = le16_to_cpu(portsts->wPortChange);
>>> +
>>> +			if ((portchange&  USB_PORT_STAT_C_CONNECTION) ==
>>> +				(portstatus&  USB_PORT_STAT_CONNECTION))
>>
>> I don't know if there is any corner case when the above check
>> will always fail and so it will always wait a maximal delay time.
>> Are those registers that identical, or can there be differences?
>
> Never mind, my mistake, USB_PORT_STAT_C_CONNECTION and USB_PORT_STAT_CONNECTION
> are the same bit in the register.
>
>>
>>> +				break;
>>> +
>>> +			mdelay(100);
>>> +		} while (get_timer(start)<  CONFIG_SYS_HZ * 10);
>>
>> Is there any justification for the CONFIG_SYS_HZ * 10?
>> I would be much more fine with this patch if there were any
>> (even just test based * 2) reason for that number.
>
> Once you address this one, feel free to add:
> Acked-by: Igor Grinberg<grinberg@compulab.co.il>
>

Thanks Igor, let me wait for Marek's comments also

>>
>>>
>>> -		if (usb_get_port_status(dev, i + 1, portsts)<  0) {
>>> -			USB_HUB_PRINTF("get_port_status failed\n");
>>> +		if (ret<  0)
>>>   			continue;
>>> -		}
>>>
>>> -		portstatus = le16_to_cpu(portsts->wPortStatus);
>>> -		portchange = le16_to_cpu(portsts->wPortChange);
>>>   		USB_HUB_PRINTF("Port %d Status %X Change %X\n",
>>>   				i + 1, portstatus, portchange);
>>>
>>
>
Vipin Kumar Dec. 12, 2012, 9:54 a.m. UTC | #4
>> +		ulong start = get_timer(0);
>> +
>> +		do {
>> +			ret = usb_get_port_status(dev, i + 1, portsts);
>> +			if (ret<  0) {
>> +				USB_HUB_PRINTF("get_port_status failed\n");
>> +				break;
>> +			}
>> +
>> +			portstatus = le16_to_cpu(portsts->wPortStatus);
>> +			portchange = le16_to_cpu(portsts->wPortChange);
>> +
>> +			if ((portchange&  USB_PORT_STAT_C_CONNECTION) ==
>> +				(portstatus&  USB_PORT_STAT_CONNECTION))
>
> I don't know if there is any corner case when the above check
> will always fail and so it will always wait a maximal delay time.
> Are those registers that identical, or can there be differences?
>
>> +				break;
>> +
>> +			mdelay(100);
>> +		} while (get_timer(start)<  CONFIG_SYS_HZ * 10);
>
> Is there any justification for the CONFIG_SYS_HZ * 10?
> I would be much more fine with this patch if there were any
> (even just test based * 2) reason for that number.
>

Not really. Just a practical test.
Marek, can I have comments from you as well

Thanks
Vipin
Marek Vasut Dec. 12, 2012, 11:25 a.m. UTC | #5
Dear Vipin Kumar,

> >> +		ulong start = get_timer(0);
> >> +
> >> +		do {
> >> +			ret = usb_get_port_status(dev, i + 1, portsts);
> >> +			if (ret<  0) {
> >> +				USB_HUB_PRINTF("get_port_status failed\n");
> >> +				break;
> >> +			}
> >> +
> >> +			portstatus = le16_to_cpu(portsts->wPortStatus);
> >> +			portchange = le16_to_cpu(portsts->wPortChange);
> >> +
> >> +			if ((portchange&  USB_PORT_STAT_C_CONNECTION) ==
> >> +				(portstatus&  USB_PORT_STAT_CONNECTION))
> > 
> > I don't know if there is any corner case when the above check
> > will always fail and so it will always wait a maximal delay time.
> > Are those registers that identical, or can there be differences?
> > 
> >> +				break;
> >> +
> >> +			mdelay(100);
> >> +		} while (get_timer(start)<  CONFIG_SYS_HZ * 10);
> > 
> > Is there any justification for the CONFIG_SYS_HZ * 10?
> > I would be much more fine with this patch if there were any
> > (even just test based * 2) reason for that number.
> 
> Not really. Just a practical test.
> Marek, can I have comments from you as well
> 

Sorry, I'm really busy these days. I went through it and I see Igor still has 
some comment. Just fix that one and I'm good.

Best regards,
Marek Vasut
Igor Grinberg Dec. 12, 2012, 11:40 a.m. UTC | #6
On 12/12/12 11:54, Vipin Kumar wrote:
> 
>>> +        ulong start = get_timer(0);
>>> +
>>> +        do {
>>> +            ret = usb_get_port_status(dev, i + 1, portsts);
>>> +            if (ret<  0) {
>>> +                USB_HUB_PRINTF("get_port_status failed\n");
>>> +                break;
>>> +            }
>>> +
>>> +            portstatus = le16_to_cpu(portsts->wPortStatus);
>>> +            portchange = le16_to_cpu(portsts->wPortChange);
>>> +
>>> +            if ((portchange&  USB_PORT_STAT_C_CONNECTION) ==
>>> +                (portstatus&  USB_PORT_STAT_CONNECTION))
>>
>> I don't know if there is any corner case when the above check
>> will always fail and so it will always wait a maximal delay time.
>> Are those registers that identical, or can there be differences?
>>
>>> +                break;
>>> +
>>> +            mdelay(100);
>>> +        } while (get_timer(start)<  CONFIG_SYS_HZ * 10);
>>
>> Is there any justification for the CONFIG_SYS_HZ * 10?
>> I would be much more fine with this patch if there were any
>> (even just test based * 2) reason for that number.
>>
> 
> Not really. Just a practical test.

Ok. good. can we please have a comment saying that this value
is based on observations? Thanks!
You can add my ack along with the comment in v3.

Thanks for the patch!
Vipin Kumar Dec. 12, 2012, noon UTC | #7
On 12/12/2012 5:10 PM, Igor Grinberg wrote:
> On 12/12/12 11:54, Vipin Kumar wrote:
>>
>>>> +        ulong start = get_timer(0);
>>>> +
>>>> +        do {
>>>> +            ret = usb_get_port_status(dev, i + 1, portsts);
>>>> +            if (ret<   0) {
>>>> +                USB_HUB_PRINTF("get_port_status failed\n");
>>>> +                break;
>>>> +            }
>>>> +
>>>> +            portstatus = le16_to_cpu(portsts->wPortStatus);
>>>> +            portchange = le16_to_cpu(portsts->wPortChange);
>>>> +
>>>> +            if ((portchange&   USB_PORT_STAT_C_CONNECTION) ==
>>>> +                (portstatus&   USB_PORT_STAT_CONNECTION))
>>>
>>> I don't know if there is any corner case when the above check
>>> will always fail and so it will always wait a maximal delay time.
>>> Are those registers that identical, or can there be differences?
>>>
>>>> +                break;
>>>> +
>>>> +            mdelay(100);
>>>> +        } while (get_timer(start)<   CONFIG_SYS_HZ * 10);
>>>
>>> Is there any justification for the CONFIG_SYS_HZ * 10?
>>> I would be much more fine with this patch if there were any
>>> (even just test based * 2) reason for that number.
>>>
>>
>> Not really. Just a practical test.
>
> Ok. good. can we please have a comment saying that this value
> is based on observations? Thanks!
> You can add my ack along with the comment in v3.
>
> Thanks for the patch!
>

Thanks Igor
Marek, I am waiting for your comments now, if any

-Vipin
Vipin Kumar Dec. 13, 2012, 6:11 a.m. UTC | #8
On 12/12/2012 4:55 PM, Marek Vasut wrote:
> Dear Vipin Kumar,
>
>>>> +		ulong start = get_timer(0);
>>>> +
>>>> +		do {
>>>> +			ret = usb_get_port_status(dev, i + 1, portsts);
>>>> +			if (ret<   0) {
>>>> +				USB_HUB_PRINTF("get_port_status failed\n");
>>>> +				break;
>>>> +			}
>>>> +
>>>> +			portstatus = le16_to_cpu(portsts->wPortStatus);
>>>> +			portchange = le16_to_cpu(portsts->wPortChange);
>>>> +
>>>> +			if ((portchange&   USB_PORT_STAT_C_CONNECTION) ==
>>>> +				(portstatus&   USB_PORT_STAT_CONNECTION))
>>>
>>> I don't know if there is any corner case when the above check
>>> will always fail and so it will always wait a maximal delay time.
>>> Are those registers that identical, or can there be differences?
>>>
>>>> +				break;
>>>> +
>>>> +			mdelay(100);
>>>> +		} while (get_timer(start)<   CONFIG_SYS_HZ * 10);
>>>
>>> Is there any justification for the CONFIG_SYS_HZ * 10?
>>> I would be much more fine with this patch if there were any
>>> (even just test based * 2) reason for that number.
>>
>> Not really. Just a practical test.
>> Marek, can I have comments from you as well
>>
>
> Sorry, I'm really busy these days. I went through it and I see Igor still has
> some comment. Just fix that one and I'm good.
>

Thanks marek, I would send a v3 soon

> Best regards,
> Marek Vasut
> .
>
diff mbox

Patch

diff --git a/common/usb_hub.c b/common/usb_hub.c
index e4a1201..3a66b0e 100644
--- a/common/usb_hub.c
+++ b/common/usb_hub.c
@@ -396,14 +396,29 @@  static int usb_hub_configure(struct usb_device *dev)
 	for (i = 0; i < dev->maxchild; i++) {
 		ALLOC_CACHE_ALIGN_BUFFER(struct usb_port_status, portsts, 1);
 		unsigned short portstatus, portchange;
+		int ret;
+		ulong start = get_timer(0);
+
+		do {
+			ret = usb_get_port_status(dev, i + 1, portsts);
+			if (ret < 0) {
+				USB_HUB_PRINTF("get_port_status failed\n");
+				break;
+			}
+
+			portstatus = le16_to_cpu(portsts->wPortStatus);
+			portchange = le16_to_cpu(portsts->wPortChange);
+
+			if ((portchange & USB_PORT_STAT_C_CONNECTION) ==
+				(portstatus & USB_PORT_STAT_CONNECTION))
+				break;
+
+			mdelay(100);
+		} while (get_timer(start) < CONFIG_SYS_HZ * 10);
 
-		if (usb_get_port_status(dev, i + 1, portsts) < 0) {
-			USB_HUB_PRINTF("get_port_status failed\n");
+		if (ret < 0)
 			continue;
-		}
 
-		portstatus = le16_to_cpu(portsts->wPortStatus);
-		portchange = le16_to_cpu(portsts->wPortChange);
 		USB_HUB_PRINTF("Port %d Status %X Change %X\n",
 				i + 1, portstatus, portchange);