Skip to contentSkip to conversation

PROBLEM: usb not working with 2.4.8-ac8

DISCUSSION Pete Zaitcev 3 participants 6 messages Aug 22, 2001 – Aug 24, 2001 1 message not in the archive USB

lore
Share & tools
lore

A message that is not in the archive (sent off-list or not yet received): [email protected]

#1 lore raw
Quoted 1 line

Looks like the change int he usb_start_wait_urb code is a problem.

Yes, something was not right with my change.
I am trying to coax people into testing this (on top of -ac8):

drivers/usb/usb.c +11 -4
@@ -1080,10 +1080,17 @@
 	current->state = TASK_RUNNING;
 	remove_wait_queue(&awd.wqh, &wait);
 
-	if (!timeout) {
-		printk("usb_control/bulk_msg: timeout\n");
-		usb_unlink_urb(urb);  // remove urb safely
-		status = -ETIMEDOUT;
+	if (!awd.done) {
+		if (urb->status != -EINPROGRESS) {	/* No callback?!! */
+			printk(KERN_ERR "usb: raced timeout, "
+			    "pipe 0x%x status %d time left %d\n",
+			    urb->pipe, urb->status, timeout);
+			status = urb->status;
+		} else {
+			printk("usb_control/bulk_msg: timeout\n");
+			usb_unlink_urb(urb);  // remove urb safely
+			status = -ETIMEDOUT;
+		}
 	} else
 		status = urb->status;
 
Quoted 2 lines

I suspect either you need to add wmb() and rmb() to stop misoptimisations on done (along with making it (!timeout && !awd.done)

Arjan said so too - I'll add them later just in case. About (!timeout && !awd.done) - it's not going to be enough, I think. I suspect that callback is not delivered at all in some circumstances, or something really screwy like that.

Quoted 2 lines

there is a signal related problem - if so making it set the state to TASK_UNINTERRUPTIBLE might cure it

I tried that first and it worked, but someone disagreed. Dunno...

-- Pete

#2 lore raw
In reply to a message not in the archive

Running 2.4.8-ac7 using the alternate uhci driver both my USB keyboard and mouse work fine. I can't use the regular uhci driver because it aparently has SMP issues with keyboards and like to hard lock the entire system, no oops or anything, if any LED key (numlock,capslock,scrolllock) is pressed enough times to turn an LED on and then off. Using 2.4.8-ac8 with the patch from below at least works more than stock 2.4.8-ac8 but I still get failures: specifically the regular uhci driver seems to work perfectly except for the issue noted above. But my uchi controller using the alternate uhci driver on 2.4.8-ac8 results in an unusable system, and with the patch below kind of works. By kind of I mean that it doesn't oops and there aren't any of the couldn't assign id type messages but I get a ton of the "raced timeout" messages and the mouse and keyboard only sporadically work, the really weird thing is that while they sporadically work for X and the console, SysRq keys on the USB keyboard seem to be perfectly functional. I don't feel that I need both drivers to work all the time, but it would be nice to either get the regular uhci driver stable with my keyboard and SMP motherboard, or get a functional alternate uchi in -ac again. Hope that helps in at least some small way to figure out what happend.

Jordan

Quoted 50 lines · Pete Zaitcev
Quoted 2 lines

Looks like the change int he usb_start_wait_urb code is a problem.

Yes, something was not right with my change.
I am trying to coax people into testing this (on top of -ac8):

drivers/usb/usb.c Tue Aug 21 16:02:01 2001 renamed from drivers/usb/usb.c Tue Aug 21 14:39:55 2001 +11 -4
@@ -1080,10 +1080,17 @@
        current->state = TASK_RUNNING;
        remove_wait_queue(&awd.wqh, &wait);
 
-       if (!timeout) {
-               printk("usb_control/bulk_msg: timeout\n");
-               usb_unlink_urb(urb);  // remove urb safely
-               status = -ETIMEDOUT;
+       if (!awd.done) {
+               if (urb->status != -EINPROGRESS) {      /* No callback?!! */
+                       printk(KERN_ERR "usb: raced timeout, "
+                           "pipe 0x%x status %d time left %d\n",
+                           urb->pipe, urb->status, timeout);
+                       status = urb->status;
+               } else {
+                       printk("usb_control/bulk_msg: timeout\n");
+                       usb_unlink_urb(urb);  // remove urb safely
+                       status = -ETIMEDOUT;
+               }
        } else
                status = urb->status;
 
Quoted 3 lines

I suspect either you need to add wmb() and rmb() to stop misoptimisations on done (along with making it (!timeout && !awd.done)

Arjan said so too - I'll add them later just in case. About (!timeout && !awd.done) - it's not going to be enough, I think. I suspect that callback is not delivered at all in some circumstances, or something really screwy like that.

Quoted 2 lines

there is a signal related problem - if so making it set the state to TASK_UNINTERRUPTIBLE might cure it

I tried that first and it worked, but someone disagreed. Dunno...

-- Pete
-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to [email protected]
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/

#3 lore raw
In reply to a message not in the archive
Quoted 11 lines

Date: Wed, 22 Aug 2001 01:48:57 -0500
From: Jordan Breeding <[email protected]>
To: Pete Zaitcev <[email protected]>,
Linux Kernel <[email protected]>

Running 2.4.8-ac7 using the alternate uhci driver both my USB keyboard and mouse work fine. I can't use the regular uhci driver because it aparently has SMP issues with keyboards and like to hard lock the entire system, no oops or anything, if any LED key (numlock,capslock,scrolllock) is pressed enough times to turn an LED on and then off.

I think I fixed it long ago - we shipped it with Red Hat Linux 7.1 on ia64, and in errata for i386. I recall arguing about it with Georg Archer, and it was accepted into Linus tree. But perhaps not every hole was plugged.

Quoted 4 lines

Using 2.4.8-ac8 with the patch from below at least works
more than stock 2.4.8-ac8 but I still get failures: specifically the regular uhci driver seems to work perfectly except for the issue noted above.

Well, good. If you have an SMP problem - post to the list. I have 2 SMPs, one with uchi and one with ohci, which run well. People used to think that USB on SMP was a non-issue, but unfortunately companies like Dell started to ship rackmounted SMPs with USB keyboards :)

Quoted 5 lines

But my uchi controller using the alternate uhci driver on
2.4.8-ac8 results in an unusable system, and with the patch below kind of works. By kind of I mean that it doesn't oops and there aren't any of the couldn't assign id type messages but I get a ton of the "raced timeout" messages and the mouse and keyboard only sporadically work,

I think the JE uhci forgets to post a callback sometimes, so I'll look. Meanwhile, try to remove that printout - it's only for JE uhci bughunt.

-- Pete

#4 lore raw
In reply to a message not in the archive

The usb-uhci and ohci worked fine, so I poked uhci a little bit and made it all work, at least with my setup. Apparently, sometimes uhci returns a success (0) from submit_urb, but forgets to deliver a completion callback.

The fix is a Johannes' territory and I not so sure of my way there, so perhaps a better one may be forthcoming.

I left the diagnostic printout in for usb_start_wait_urb, we may drop it later. It must not be triggered if everything works as planned.

-- Pete

drivers/usb/uhci.c +18 -10
diff -ur -X dontdiff linux-2.4.8-ac9/drivers/usb/uhci.c linux-2.4.8-ac9-niph/drivers/usb/uhci.c
@@ -1471,6 +1471,7 @@
 
 static int uhci_submit_urb(struct urb *urb)
 {
+	struct usb_device *dev;
 	int ret = -EINVAL;
 	struct uhci *uhci;
 	unsigned long flags;
@@ -1480,15 +1481,16 @@
 	if (!urb)
 		return -EINVAL;
 
-	if (!urb->dev || !urb->dev->bus || !urb->dev->bus->hcpriv) {
+	dev = urb->dev;
+	if (!dev || !dev->bus || !dev->bus->hcpriv) {
 		warn("uhci_submit_urb: urb %p belongs to disconnected device or bus?", urb);
 		return -ENODEV;
 	}
 
-	uhci = (struct uhci *)urb->dev->bus->hcpriv;
+	uhci = (struct uhci *)dev->bus->hcpriv;
 
 	INIT_LIST_HEAD(&urb->urb_list);
-	usb_inc_dev_use(urb->dev);
+	usb_inc_dev_use(dev);
 
 	spin_lock_irqsave(&urb->lock, flags);
 
@@ -1497,7 +1499,7 @@
 		dbg("uhci_submit_urb: urb not available to submit (status = %d)", urb->status);
 		/* Since we can have problems on the out path */
 		spin_unlock_irqrestore(&urb->lock, flags);
-		usb_dec_dev_use(urb->dev);
+		usb_dec_dev_use(dev);
 
 		return ret;
 	}
@@ -1516,7 +1518,7 @@
 	}
 
 	/* Short circuit the virtual root hub */
-	if (urb->dev == uhci->rh.dev) {
+	if (dev == uhci->rh.dev) {
 		ret = rh_submit_urb(urb);
 
 		goto out;
@@ -1528,13 +1530,13 @@
 		break;
 	case PIPE_INTERRUPT:
 		if (urb->bandwidth == 0) {	/* not yet checked/allocated */
-			bustime = usb_check_bandwidth(urb->dev, urb);
+			bustime = usb_check_bandwidth(dev, urb);
 			if (bustime < 0)
 				ret = bustime;
 			else {
 				ret = uhci_submit_interrupt(urb);
 				if (ret == -EINPROGRESS)
-					usb_claim_bandwidth(urb->dev, urb, bustime, 0);
+					usb_claim_bandwidth(dev, urb, bustime, 0);
 			}
 		} else		/* bandwidth is already set */
 			ret = uhci_submit_interrupt(urb);
@@ -1548,7 +1550,7 @@
 				ret = -EINVAL;
 				break;
 			}
-			bustime = usb_check_bandwidth(urb->dev, urb);
+			bustime = usb_check_bandwidth(dev, urb);
 			if (bustime < 0) {
 				ret = bustime;
 				break;
@@ -1556,7 +1558,7 @@
 
 			ret = uhci_submit_isochronous(urb);
 			if (ret == -EINPROGRESS)
-				usb_claim_bandwidth(urb->dev, urb, bustime, 1);
+				usb_claim_bandwidth(dev, urb, bustime, 1);
 		} else		/* bandwidth is already set */
 			ret = uhci_submit_isochronous(urb);
 		break;
@@ -1578,8 +1580,14 @@
 
 	uhci_unlink_generic(uhci, urb);
 	uhci_destroy_urb_priv(urb);
+	if (ret == 0) {				/* N.B. Done, must notify */
+		/* uhci_call_completion(urb); */ /* ->> uhci_destroy_urb_priv */
+		urb->dev = NULL;
+		if (urb->complete)
+			urb->complete(urb);
+	}
 
-	usb_dec_dev_use(urb->dev);
+	usb_dec_dev_use(dev);
 
 	return ret;
 }
drivers/usb/usb.c +16 -10
diff -ur -X dontdiff linux-2.4.8-ac9/drivers/usb/usb.c linux-2.4.8-ac9-niph/drivers/usb/usb.c
@@ -1085,10 +1085,17 @@
 	set_current_state(TASK_RUNNING);
 	remove_wait_queue(&awd.wqh, &wait);
 
-	if (!timeout && !awd.done) {
-		printk("usb_control/bulk_msg: timeout\n");
-		usb_unlink_urb(urb);  // remove urb safely
-		status = -ETIMEDOUT;
+	if (!awd.done) {
+		if (urb->status != -EINPROGRESS) {	/* No callback?!! */
+			printk(KERN_ERR "usb: raced timeout, "
+			    "pipe 0x%x status %d time left %d\n",
+			    urb->pipe, urb->status, timeout);
+			status = urb->status;
+		} else {
+			printk("usb_control/bulk_msg: timeout\n");
+			usb_unlink_urb(urb);  // remove urb safely
+			status = -ETIMEDOUT;
+		}
 	} else
 		status = urb->status;
 
@@ -1111,16 +1118,15 @@
 	urb = usb_alloc_urb(0);
 	if (!urb)
 		return -ENOMEM;
-  
-	FILL_CONTROL_URB(urb, usb_dev, pipe, (unsigned char*)cmd, data, len,    /* build urb */  
-		   (usb_complete_t)usb_api_blocking_completion,0);
+
+	FILL_CONTROL_URB(urb, usb_dev, pipe, (unsigned char*)cmd, data, len,
+		   usb_api_blocking_completion, 0);
 
 	retv = usb_start_wait_urb(urb, timeout, &length);
 	if (retv < 0)
 		return retv;
 	else
 		return length;
-	
 }
 
 /**
@@ -1201,8 +1207,8 @@
 	if (!urb)
 		return -ENOMEM;
 
-	FILL_BULK_URB(urb,usb_dev,pipe,(unsigned char*)data,len,   /* build urb */
-			(usb_complete_t)usb_api_blocking_completion,0);
+	FILL_BULK_URB(urb, usb_dev, pipe, data, len,
+		    usb_api_blocking_completion, 0);
 
 	return usb_start_wait_urb(urb,timeout,actual_length);
 }
#5 lore raw
In reply to a message not in the archive
Quoted 7 lines · Pete Zaitcev

The usb-uhci and ohci worked fine, so I poked uhci a little bit and made it all work, at least with my setup. Apparently, sometimes uhci returns a success (0) from submit_urb, but forgets to deliver a completion callback.

The fix is a Johannes' territory and I not so sure of my way there, so perhaps a better one may be forthcoming.

Forgets may or may not be true. Success (0) from submit_urb only means the URB was scheduled.

You may not receive a completion callback if the device NAK's the transfer forever, or if there is a bug in uhci.c where the URB didn't really get scheduled.

What was you test scenario where you didn't see a completion callback?

Quoted 89 lines

diff -ur -X dontdiff linux-2.4.8-ac9/drivers/usb/uhci.c linux-2.4.8-ac9-niph/drivers/usb/uhci.c

drivers/usb/uhci.c +13 -9
@@ -1471,6 +1471,7 @@
 
 static int uhci_submit_urb(struct urb *urb)
 {
+	struct usb_device *dev;
 	int ret = -EINVAL;
 	struct uhci *uhci;
 	unsigned long flags;
@@ -1480,15 +1481,16 @@
 	if (!urb)
 		return -EINVAL;
 
-	if (!urb->dev || !urb->dev->bus || !urb->dev->bus->hcpriv) {
+	dev = urb->dev;
+	if (!dev || !dev->bus || !dev->bus->hcpriv) {
 		warn("uhci_submit_urb: urb %p belongs to disconnected device or bus?", urb);
 		return -ENODEV;
 	}
 
-	uhci = (struct uhci *)urb->dev->bus->hcpriv;
+	uhci = (struct uhci *)dev->bus->hcpriv;
 
 	INIT_LIST_HEAD(&urb->urb_list);
-	usb_inc_dev_use(urb->dev);
+	usb_inc_dev_use(dev);
 
 	spin_lock_irqsave(&urb->lock, flags);
 
@@ -1497,7 +1499,7 @@
 		dbg("uhci_submit_urb: urb not available to submit (status = %d)", urb->status);
 		/* Since we can have problems on the out path */
 		spin_unlock_irqrestore(&urb->lock, flags);
-		usb_dec_dev_use(urb->dev);
+		usb_dec_dev_use(dev);
 
 		return ret;
 	}
@@ -1516,7 +1518,7 @@
 	}
 
 	/* Short circuit the virtual root hub */
-	if (urb->dev == uhci->rh.dev) {
+	if (dev == uhci->rh.dev) {
 		ret = rh_submit_urb(urb);
 
 		goto out;
@@ -1528,13 +1530,13 @@
 		break;
 	case PIPE_INTERRUPT:
 		if (urb->bandwidth == 0) {	/* not yet checked/allocated */
-			bustime = usb_check_bandwidth(urb->dev, urb);
+			bustime = usb_check_bandwidth(dev, urb);
 			if (bustime < 0)
 				ret = bustime;
 			else {
 				ret = uhci_submit_interrupt(urb);
 				if (ret == -EINPROGRESS)
-					usb_claim_bandwidth(urb->dev, urb, bustime, 0);
+					usb_claim_bandwidth(dev, urb, bustime, 0);
 			}
 		} else		/* bandwidth is already set */
 			ret = uhci_submit_interrupt(urb);
@@ -1548,7 +1550,7 @@
 				ret = -EINVAL;
 				break;
 			}
-			bustime = usb_check_bandwidth(urb->dev, urb);
+			bustime = usb_check_bandwidth(dev, urb);
 			if (bustime < 0) {
 				ret = bustime;
 				break;
@@ -1556,7 +1558,7 @@
 
 			ret = uhci_submit_isochronous(urb);
 			if (ret == -EINPROGRESS)
-				usb_claim_bandwidth(urb->dev, urb, bustime, 1);
+				usb_claim_bandwidth(dev, urb, bustime, 1);
 		} else		/* bandwidth is already set */
 			ret = uhci_submit_isochronous(urb);
 		break;
@@ -1578,8 +1580,14 @@
 
 	uhci_unlink_generic(uhci, urb);
 	uhci_destroy_urb_priv(urb);
+	if (ret == 0) {				/* N.B. Done, must notify */
+		/* uhci_call_completion(urb); */ /* ->> uhci_destroy_urb_priv */

drivers/usb/uhci.c line 1593

Quoted 10 lines
drivers/usb/uhci.c +5 -1
+		urb->dev = NULL;
+		if (urb->complete)
+			urb->complete(urb);
+	}
 
-	usb_dec_dev_use(urb->dev);
+	usb_dec_dev_use(dev);
 
 	return ret;
 }

What's all of this for? Protecting against an urb->dev race condition?

JE

#6 lore raw
In reply to a message not in the archive
Quoted 3 lines · Pete Zaitcev
Quoted 1 line

What was you test scenario where you didn't see a completion callback?

The root hub emulation never posts one.

Hmm, it should. I'll check that again.

Quoted 7 lines
Quoted 7 lines
Quoted 7 lines
(quoted diff) +6 -0
+	if (ret == 0) {				/* N.B. Done, must notify */
+		/* uhci_call_completion(urb); */ /* ->> uhci_destroy_urb_priv */
+		urb->dev = NULL;
+		if (urb->complete)
+			urb->complete(urb);
+	}
Quoted 6 lines
Quoted 4 lines

Review

Quoted 2 lines
(quoted diff) +1 -1
-	usb_dec_dev_use(urb->dev);
+	usb_dec_dev_use(dev);

What's all of this for? Protecting against an urb->dev race condition?

No race, but we cannot use urb after callback.

Ahh, good point.

Thanks.

JE