Subject: kern/32172: USB network drivers sleep in interrupt if stalled
To: None <kern-bug-people@netbsd.org, gnats-admin@netbsd.org,>
From: Matthew Orgass <darkstar@city-net.com>
List: netbsd-bugs
Date: 11/27/2005 03:54:01
>Number:         32172
>Category:       kern
>Synopsis:       USB network drivers sleep in interrupt if stalled
>Confidential:   no
>Severity:       serious
>Priority:       medium
>Responsible:    kern-bug-people
>State:          open
>Class:          sw-bug
>Submitter-Id:   net
>Arrival-Date:   Sun Nov 27 03:54:01 +0000 2005
>Originator:     darkstar@city-net.com
>Release:        NetBSD 2.0_RC4
>Organization:
>Description:

  The USB network drivers will, if stalled, call usbd_clear_endpoint_stall
from the callback, which does a synchronous transfer, which sleeps.  The
callbacks are done in soft interrupts.

>How-To-Repeat:

  I hope this would be difficult or impossible to trigger without
explicitly setting stall.  I think it might also happen if the bus traffic
looks sufficiently messed up on the device side.

>Fix:

  This patch changes them to usbd_clear_endpoint_stall_async, but will not
restart the pipe (at least an ifconfig down/up should work).  It may make
sense to have usbd_clear_endpoint_stall_async restart the pipe or else have
another way to do automatic stall clearing (maybe before the callback of the
stalled transaction) for drivers that don't intend to do anything special
when stalled.

  A comment in usbd_clear_endpoint_stall would probably be a good idea too,
but is not included in this diff.

Index: if_aue.c
===================================================================
RCS file: /cvsroot/src/sys/dev/usb/if_aue.c,v
retrieving revision 1.85.4.1
diff -u -r1.85.4.1 if_aue.c
--- if_aue.c	24 Jan 2005 21:42:10 -0000	1.85.4.1
+++ if_aue.c	27 Nov 2005 03:36:57 -0000
@@ -1058,7 +1058,7 @@
 			sc->aue_intr_errs = 0;
 		}
 		if (status == USBD_STALLED)
-			usbd_clear_endpoint_stall(sc->aue_ep[AUE_ENDPT_RX]);
+			usbd_clear_endpoint_stall_async(sc->aue_ep[AUE_ENDPT_RX]);
 		return;
 	}

@@ -1103,7 +1103,7 @@
 			sc->aue_rx_errs = 0;
 		}
 		if (status == USBD_STALLED)
-			usbd_clear_endpoint_stall(sc->aue_ep[AUE_ENDPT_RX]);
+			usbd_clear_endpoint_stall_async(sc->aue_ep[AUE_ENDPT_RX]);
 		goto done;
 	}

@@ -1204,7 +1204,7 @@
 		printf("%s: usb error on tx: %s\n", USBDEVNAME(sc->aue_dev),
 		    usbd_errstr(status));
 		if (status == USBD_STALLED)
-			usbd_clear_endpoint_stall(sc->aue_ep[AUE_ENDPT_TX]);
+			usbd_clear_endpoint_stall_async(sc->aue_ep[AUE_ENDPT_TX]);
 		splx(s);
 		return;
 	}
Index: if_cue.c
===================================================================
RCS file: /cvsroot/src/sys/dev/usb/if_cue.c,v
retrieving revision 1.40
diff -u -r1.40 if_cue.c
--- if_cue.c	11 Jul 2002 21:14:26 -0000	1.40
+++ if_cue.c	27 Nov 2005 03:36:59 -0000
@@ -797,7 +797,7 @@
 			sc->cue_rx_errs = 0;
 		}
 		if (status == USBD_STALLED)
-			usbd_clear_endpoint_stall(sc->cue_ep[CUE_ENDPT_RX]);
+			usbd_clear_endpoint_stall_async(sc->cue_ep[CUE_ENDPT_RX]);
 		goto done;
 	}

@@ -890,7 +890,7 @@
 		printf("%s: usb error on tx: %s\n", USBDEVNAME(sc->cue_dev),
 		    usbd_errstr(status));
 		if (status == USBD_STALLED)
-			usbd_clear_endpoint_stall(sc->cue_ep[CUE_ENDPT_TX]);
+			usbd_clear_endpoint_stall_async(sc->cue_ep[CUE_ENDPT_TX]);
 		splx(s);
 		return;
 	}
Index: if_kue.c
===================================================================
RCS file: /cvsroot/src/sys/dev/usb/if_kue.c,v
retrieving revision 1.50
diff -u -r1.50 if_kue.c
--- if_kue.c	16 Jul 2002 22:00:31 -0000	1.50
+++ if_kue.c	27 Nov 2005 03:37:01 -0000
@@ -741,7 +741,7 @@
 			sc->kue_rx_errs = 0;
 		}
 		if (status == USBD_STALLED)
-			usbd_clear_endpoint_stall(sc->kue_ep[KUE_ENDPT_RX]);
+			usbd_clear_endpoint_stall_async(sc->kue_ep[KUE_ENDPT_RX]);
 		goto done;
 	}

@@ -842,7 +842,7 @@
 		printf("%s: usb error on tx: %s\n", USBDEVNAME(sc->kue_dev),
 		    usbd_errstr(status));
 		if (status == USBD_STALLED)
-			usbd_clear_endpoint_stall(sc->kue_ep[KUE_ENDPT_TX]);
+			usbd_clear_endpoint_stall_async(sc->kue_ep[KUE_ENDPT_TX]);
 		splx(s);
 		return;
 	}
Index: if_uax.c
===================================================================
RCS file: /cvsroot/src/sys/dev/usb/Attic/if_uax.c,v
retrieving revision 1.10
diff -u -r1.10 if_uax.c
--- if_uax.c	22 Dec 2003 10:27:51 -0000	1.10
+++ if_uax.c	27 Nov 2005 03:37:03 -0000
@@ -896,7 +896,7 @@
 		printf("%s: usb error on tx: %s\n", USBDEVNAME(sc->sc_dev),
 		    usbd_errstr(status));
 		if (status == USBD_STALLED)
-			usbd_clear_endpoint_stall(sc->sc_ep[UAX_ENDPT_TX]);
+			usbd_clear_endpoint_stall_async(sc->sc_ep[UAX_ENDPT_TX]);
 		splx(s);
 		return;
 	}
@@ -1089,7 +1089,7 @@
 			sc->sc_rx_errs = 0;
 		}
 		if (status == USBD_STALLED)
-			usbd_clear_endpoint_stall(sc->sc_ep[UAX_ENDPT_RX]);
+			usbd_clear_endpoint_stall_async(sc->sc_ep[UAX_ENDPT_RX]);
 		goto done;
 	}

@@ -1419,7 +1419,7 @@
 			sc->sc_intr_errs = 0;
 		}
 		if (status == USBD_STALLED)
-			usbd_clear_endpoint_stall(sc->sc_ep[UAX_ENDPT_RX]);
+			usbd_clear_endpoint_stall_async(sc->sc_ep[UAX_ENDPT_RX]);
 		return;
 	}

Index: if_udav.c
===================================================================
RCS file: /cvsroot/src/sys/dev/usb/if_udav.c,v
retrieving revision 1.2.4.1
diff -u -r1.2.4.1 if_udav.c
--- if_udav.c	24 Jan 2005 21:37:45 -0000	1.2.4.1
+++ if_udav.c	27 Nov 2005 03:37:05 -0000
@@ -1086,7 +1086,7 @@
 		       usbd_errstr(status));
 		if (status == USBD_STALLED) {
 			sc->sc_refcnt++;
-			usbd_clear_endpoint_stall(sc->sc_pipe_tx);
+			usbd_clear_endpoint_stall_async(sc->sc_pipe_tx);
 			if (--sc->sc_refcnt < 0)
 				usb_detach_wakeup(USBDEV(sc->sc_dev));
 		}
@@ -1133,7 +1133,7 @@
 		}
 		if (status == USBD_STALLED) {
 			sc->sc_refcnt++;
-			usbd_clear_endpoint_stall(sc->sc_pipe_rx);
+			usbd_clear_endpoint_stall_async(sc->sc_pipe_rx);
 			if (--sc->sc_refcnt < 0)
 				usb_detach_wakeup(USBDEV(sc->sc_dev));
 		}
Index: if_upl.c
===================================================================
RCS file: /cvsroot/src/sys/dev/usb/if_upl.c,v
retrieving revision 1.19
diff -u -r1.19 if_upl.c
--- if_upl.c	11 Jul 2002 21:14:26 -0000	1.19
+++ if_upl.c	27 Nov 2005 03:37:06 -0000
@@ -535,7 +535,7 @@
 			sc->sc_rx_errs = 0;
 		}
 		if (status == USBD_STALLED)
-			usbd_clear_endpoint_stall(sc->sc_ep[UPL_ENDPT_RX]);
+			usbd_clear_endpoint_stall_async(sc->sc_ep[UPL_ENDPT_RX]);
 		goto done;
 	}

@@ -625,7 +625,7 @@
 		printf("%s: usb error on tx: %s\n", USBDEVNAME(sc->sc_dev),
 		    usbd_errstr(status));
 		if (status == USBD_STALLED)
-			usbd_clear_endpoint_stall(sc->sc_ep[UPL_ENDPT_TX]);
+			usbd_clear_endpoint_stall_async(sc->sc_ep[UPL_ENDPT_TX]);
 		splx(s);
 		return;
 	}
@@ -841,7 +841,7 @@
 			sc->sc_intr_errs = 0;
 		}
 		if (status == USBD_STALLED)
-			usbd_clear_endpoint_stall(sc->sc_ep[UPL_ENDPT_RX]);
+			usbd_clear_endpoint_stall_async(sc->sc_ep[UPL_ENDPT_RX]);
 		return;
 	}

Index: if_url.c
===================================================================
RCS file: /cvsroot/src/sys/dev/usb/if_url.c,v
retrieving revision 1.8.2.1.2.1
diff -u -r1.8.2.1.2.1 if_url.c
--- if_url.c	24 Jan 2005 21:42:31 -0000	1.8.2.1.2.1
+++ if_url.c	27 Nov 2005 03:37:09 -0000
@@ -966,7 +966,7 @@
 		       usbd_errstr(status));
 		if (status == USBD_STALLED) {
 			sc->sc_refcnt++;
-			usbd_clear_endpoint_stall(sc->sc_pipe_tx);
+			usbd_clear_endpoint_stall_async(sc->sc_pipe_tx);
 			if (--sc->sc_refcnt < 0)
 				usb_detach_wakeup(USBDEV(sc->sc_dev));
 		}
@@ -1013,7 +1013,7 @@
 		}
 		if (status == USBD_STALLED) {
 			sc->sc_refcnt++;
-			usbd_clear_endpoint_stall(sc->sc_pipe_rx);
+			usbd_clear_endpoint_stall_async(sc->sc_pipe_rx);
 			if (--sc->sc_refcnt < 0)
 				usb_detach_wakeup(USBDEV(sc->sc_dev));
 		}