> I'm starting to get a few reports of ehci probe issues with the latest
> opensuse kernel:
>       https://bugzilla.novell.com/show_bug.cgi?id=100533
> 
> that sound a lot like issues that you fixed already.  The kernel they
> are using is 2.6.13-rc6-git8 or so, with your ehci patches that are in
> the -mm tree added for good measure.
> 
> Any thoughts about this?

I think they're most likely to be usbcore issues.  And they certainly
don't reproduce on hardware I have here!

The attached patch is compile-tested, and tweaks a bunch of things
that might be causing trouble in the enumeration paths.  Maybe some
of the tweaks will help, and we could get this fixed for 2.6.13...

- Dave
This is an experimental patch to see if various things may help
get rid of some intermittent hardware-specific enumeration problems
we've been seeing over the last year, after various usbcore updates
to the enumeration code.

Some changes relax some timings, on the notion that maybe not
all devices obey the specs:

  - Wait a minimum of 200 msec after powering up a hub's ports
    before expecting them to behave.

  - Wait extra time after port reset before we expect the device
    to behave ... 10msec isn't all that much to some hardware,
    so make it 50 msec.

Other changes make the enumeration code more lenient:

  - Only interrogate full speed devices about ep0 maxpacket size.

  - Once we know the ep0 maxpacket size we're using, don't bother
    trying to read it again.

  - After a set_address() error, reset the port.  Failures in that
    request leave the device's address indeterminate.

This is EXPERIMENTAL and has only been compile-tested.  Post results
to linux-usb-devel.


--- g26.orig/drivers/usb/core/hub.c	2005-08-11 20:49:11.000000000 -0700
+++ g26/drivers/usb/core/hub.c	2005-08-17 13:16:12.000000000 -0700
@@ -435,6 +435,7 @@ void usb_hub_tt_clear_buffer (struct usb
 static void hub_power_on(struct usb_hub *hub)
 {
 	int port1;
+	unsigned pgood_delay = hub->descriptor->bPwrOn2PwrGood * 2;
 
 	/* if hub supports power switching, enable power on each port */
 	if ((hub->descriptor->wHubCharacteristics & HUB_CHAR_LPSM) < 2) {
@@ -444,8 +445,8 @@ static void hub_power_on(struct usb_hub 
 					USB_PORT_FEAT_POWER);
 	}
 
-	/* Wait for power to be enabled */
-	msleep(hub->descriptor->bPwrOn2PwrGood * 2);
+	/* Wait 200+ msec for power to be enabled */
+	msleep(max(pgood_delay, (unsigned) 200));
 }
 
 static void hub_quiesce(struct usb_hub *hub)
@@ -1401,8 +1402,8 @@ static int hub_port_reset(struct usb_hub
 		/* return on disconnect or reset */
 		switch (status) {
 		case 0:
-			/* TRSTRCY = 10 ms */
-			msleep(10);
+			/* TRSTRCY = 10 ms; plus some extra */
+			msleep(10 + 40);
 			/* FALL THROUGH */
 		case -ENOTCONN:
 		case -ENODEV:
@@ -2153,6 +2154,7 @@ hub_port_init (struct usb_hub *hub, stru
 	 */
 	switch (udev->speed) {
 	case USB_SPEED_HIGH:		/* fixed at 64 */
+		udev->descriptor.bMaxPacketSize0 =
 		udev->ep0.desc.wMaxPacketSize = __constant_cpu_to_le16(64);
 		break;
 	case USB_SPEED_FULL:		/* 8, 16, 32, or 64 */
@@ -2163,6 +2165,7 @@ hub_port_init (struct usb_hub *hub, stru
 		udev->ep0.desc.wMaxPacketSize = __constant_cpu_to_le16(64);
 		break;
 	case USB_SPEED_LOW:		/* fixed at 8 */
+		udev->descriptor.bMaxPacketSize0 =
 		udev->ep0.desc.wMaxPacketSize = __constant_cpu_to_le16(8);
 		break;
 	default:
@@ -2193,7 +2196,7 @@ hub_port_init (struct usb_hub *hub, stru
  
 	/* Why interleave GET_DESCRIPTOR and SET_ADDRESS this way?
 	 * Because device hardware and firmware is sometimes buggy in
-	 * this area, and this is how Linux has done it for ages.
+	 * this area.
 	 * Change it cautiously.
 	 *
 	 * NOTE:  If USE_NEW_SCHEME() is true we will start by issuing
@@ -2204,7 +2207,8 @@ hub_port_init (struct usb_hub *hub, stru
 	 * value.
 	 */
 	for (i = 0; i < GET_DESCRIPTOR_TRIES; (++i, msleep(100))) {
-		if (USE_NEW_SCHEME(retry_counter)) {
+		if (USE_NEW_SCHEME(retry_counter)
+				&& !udev->descriptor.bMaxPacketSize0) {
 			struct usb_device_descriptor *buf;
 			int r = 0;
 
@@ -2268,22 +2272,28 @@ hub_port_init (struct usb_hub *hub, stru
 #undef GET_DESCRIPTOR_BUFSIZE
 		}
 
+		/* after set_address errors it's not clear what the
+		 * device's address will be; so reset, and be sure.
+		 */
 		for (j = 0; j < SET_ADDRESS_TRIES; ++j) {
 			retval = hub_set_address(udev);
 			if (retval >= 0)
 				break;
-			msleep(200);
+			(void) hub_port_reset(hub, port1, udev, delay);
 		}
 		if (retval < 0) {
 			dev_err(&udev->dev,
 				"device not accepting address %d, error %d\n",
 				udev->devnum, retval);
-			goto fail;
+			continue;
 		}
+
+		/* don't expect hardware to jump through needless hoops */
+		if (udev->descriptor.bMaxPacketSize0)
+			break;
  
 		/* cope with hardware quirkiness:
 		 *  - let SET_ADDRESS settle, some device hardware wants it
-		 *  - read ep0 maxpacket even for high and low speed,
   		 */
 		msleep(10);
 		if (USE_NEW_SCHEME(retry_counter))

Reply via email to