1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
|
From dvomlehn@cisco.com Mon Aug 2 16:13:11 2010
Date: Mon, 2 Aug 2010 10:46:00 -0700
From: David VomLehn <dvomlehn@cisco.com>
To: linux-usb@vger.kernel.org
Cc: greg@kroah.com
Subject: USB: Fix stuck USB generic serial driver
Message-ID: <20100802174600.GA6845@dvomlehn-lnx2.corp.sa.net>
Content-Disposition: inline
Fix USB console hang due to non-atomic URB allocation
This is intended to fix a problem seen with the Amtel sam-ba tool by
Alexander Stein (alexander.stein@systec-electronic.com). It appears
when using an A91 controller. He bisected it to commit:
8e8dce065088833fc418bfa5fbf035cb0726c04c: USB: use kfifo to buffer usb-generic serial writes
The current patch fixes a problem when using a USB serial device as the
kernel console and as /dev/console. The URB allocation is not atomic and
an URB can be doubly allocated, leading to a continual rejection of URB
submissions. The fix puts all pieces of the URB allocation in the same
spinlock-protected section of code.
Having said that...
This fix was developed because, after Alexander's email, I took a look
at my USB console and found that it, too, was experiencing a hang. I
assumed that this hang was the same as the one Alexander is seeing and
developed this fix. It's a good fix for *a* hang, but after thinking
about this a bit, I'm not sure this is a fix for *Alexander's* hang.
Signed-off-by: David VomLehn <dvomlehn@cisco.com>
Cc: stable <stable@kernel.org>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
---
drivers/usb/serial/generic.c | 5 ++++-
1 file changed, 4 insertions(+), 1 deletion(-)
--- a/drivers/usb/serial/generic.c
+++ b/drivers/usb/serial/generic.c
@@ -199,6 +199,9 @@ retry:
}
i = (int)find_first_bit(&port->write_urbs_free,
ARRAY_SIZE(port->write_urbs));
+ if (i == ARRAY_SIZE(port->write_urbs))
+ return 0;
+ clear_bit(i, &port->write_urbs_free);
spin_unlock_irqrestore(&port->lock, flags);
urb = port->write_urbs[i];
@@ -213,9 +216,9 @@ retry:
dev_err(&port->dev, "%s - error submitting urb: %d\n",
__func__, result);
clear_bit_unlock(USB_SERIAL_WRITE_BUSY, &port->flags);
+ set_bit(i, &port->write_urbs_free);
return result;
}
- clear_bit(i, &port->write_urbs_free);
spin_lock_irqsave(&port->lock, flags);
port->tx_bytes += count;
|