Go to:
Gentoo Home
Documentation
Forums
Lists
Bugs
Planet
Store
Wiki
Get Gentoo!
Gentoo's Bugzilla – Attachment 30456 Details for
Bug 49600
USB devices causes sytem to freeze when used with OHCI and EHCI modules
Home
|
New
–
[Ex]
|
Browse
|
Search
|
Privacy Policy
|
[?]
|
Reports
|
Requests
|
Help
|
New Account
|
Log In
[x]
|
Forgot Password
Login:
[x]
[patch]
7th patch
linux-2.4.23-usb-bug-90442.patch (text/plain), 7.91 KB, created by
Andrew Yates
on 2004-05-01 08:46:56 UTC
(
hide
)
Description:
7th patch
Filename:
MIME Type:
Creator:
Andrew Yates
Created:
2004-05-01 08:46:56 UTC
Size:
7.91 KB
patch
obsolete
>diff -ur linux-2.4.20-20.7.5/drivers/usb/serial/usbserial.c linux-2.4.20-20.7.5-u1/drivers/usb/serial/usbserial.c >--- linux-2.4.20-20.7.5/drivers/usb/serial/usbserial.c 2003-11-17 22:30:34.000000000 -0500 >+++ linux-2.4.20-20.7.5-u1/drivers/usb/serial/usbserial.c 2003-11-17 22:33:16.000000000 -0500 >@@ -297,6 +297,7 @@ > #include <linux/spinlock.h> > #include <linux/list.h> > #include <linux/smp_lock.h> >+#include <linux/spinlock.h> > #include <linux/usb.h> > > #ifdef CONFIG_USB_SERIAL_DEBUG >@@ -347,10 +348,24 @@ > }; > #endif > >+/* >+ * The post kludge structures and variables. >+ */ >+#define POST_BSIZE 100 /* little below 128 in total */ >+struct usb_serial_post_job { >+ struct list_head link; >+ struct usb_serial_port *port; >+ int len; >+ char buff[POST_BSIZE]; >+}; >+static spinlock_t post_lock = SPIN_LOCK_UNLOCKED; /* Also covers ->ref */ >+static struct list_head post_list = LIST_HEAD_INIT(post_list); >+static struct tq_struct post_task; > > /* local function prototypes */ > static int serial_open (struct tty_struct *tty, struct file * filp); > static void serial_close (struct tty_struct *tty, struct file * filp); >+static int __serial_write (struct usb_serial_port *port, int from_user, const unsigned char *buf, int count); > static int serial_write (struct tty_struct * tty, int from_user, const unsigned char *buf, int count); > static int serial_write_room (struct tty_struct *tty); > static int serial_chars_in_buffer (struct tty_struct *tty); >@@ -448,6 +463,53 @@ > return; > } > >+/* >+ * The post kludge. >+ * >+ * Our component drivers are hideously buggy and written by people >+ * who have difficulty understanding the concept of spinlocks. >+ * There were so many races and lockups that Greg K-H made a watershed >+ * decision to provide what is essentially a single-threaded sandbox >+ * for component drivers, protected by a semaphore. It helped a lot, but >+ * for one little problem: when tty->low_latency is set, line disciplines >+ * can call ->write from an interrupt, where the semaphore oopses. >+ * >+ * Rather than open the whole can of worms again, we just post writes >+ * into a helper which can sleep. >+ * >+ * Kernel 2.6 has a proper fix, reportedly. >+ * >+ * XXX Nothing prevents this from looping forever. >+ */ >+static void post_helper(void *arg) >+{ >+ struct usb_serial_post_job *job; >+ struct usb_serial_port *port; >+ struct usb_serial *serial; >+ unsigned int flags; >+ >+ spin_lock_irqsave(&post_lock, flags); >+ while (!list_empty(&post_list)) { >+ job = list_entry(post_list.next, struct usb_serial_post_job, link); >+ list_del(&job->link); >+ spin_unlock_irqrestore(&post_lock, flags); >+ >+ port = job->port; >+ serial = get_usb_serial (port, __FUNCTION__); >+ >+ down(&port->sem); >+ if (port->tty != NULL) >+ __serial_write(port, 0, job->buff, job->len); >+ up(&port->sem); >+ >+ kfree(job); >+ spin_lock_irqsave(&post_lock, flags); >+ if (--serial->ref == 0) >+ kfree(serial); >+ } >+ spin_unlock_irqrestore(&post_lock, flags); >+} >+ > #ifdef USES_EZUSB_FUNCTIONS > /* EZ-USB Control and Status Register. Bit 0 controls 8051 reset */ > #define CPUCS_REG 0x7F92 >@@ -576,23 +638,21 @@ > > /* if disconnect beat us to the punch here, there's nothing to do */ > if (tty->driver_data) { >+ /* post_helper(NULL); */ /* Correct, but unimportant for echo.*/ > __serial_close(port, filp); > } > > up (&port->sem); > } > >-static int serial_write (struct tty_struct * tty, int from_user, const unsigned char *buf, int count) >+static int __serial_write (struct usb_serial_port *port, int from_user, const unsigned char *buf, int count) > { >- struct usb_serial_port *port = (struct usb_serial_port *) tty->driver_data; > struct usb_serial *serial = get_usb_serial (port, __FUNCTION__); > int retval = -EINVAL; > > if (!serial) > return -ENODEV; > >- down (&port->sem); >- > dbg("%s - port %d, %d byte(s)", __FUNCTION__, port->number, count); > > if (!port->open_count) { >@@ -607,10 +667,68 @@ > retval = generic_write(port, from_user, buf, count); > > exit: >- up (&port->sem); > return retval; > } > >+static int serial_write (struct tty_struct * tty, int from_user, const unsigned char *buf, int count) >+{ >+ struct usb_serial_port *port = (struct usb_serial_port *) tty->driver_data; >+ struct usb_serial *serial = get_usb_serial (port, __FUNCTION__); >+ struct usb_serial_post_job *job; >+ unsigned long flags; >+ int rc; >+ >+ if (!in_interrupt()) { >+ /* >+ * Run post_list to reduce a possiblity of reordered writes. >+ * Tasks can make keventd to sleep, sometimes for a long time. >+ */ >+ post_helper(NULL); >+ >+ down(&port->sem); >+ rc = __serial_write(port, from_user, buf, count); >+ up(&port->sem); >+ return rc; >+ } >+ >+ if (from_user) { >+ /* >+ * This is a BUG-able offense because we cannot >+ * pagefault while in_interrupt, but we want to see >+ * something in dmesg rather than just blinking LEDs. >+ */ >+ err("user data in interrupt write"); >+ return -EINVAL; >+ } >+ >+ job = kmalloc(sizeof(struct usb_serial_post_job), GFP_ATOMIC); >+ if (job == NULL) >+ return -ENOMEM; >+ >+ job->port = port; >+ if ((job->len = count) >= POST_BSIZE) { >+ static int rate = 0; >+ /* >+ * Data loss due to extreme circumstances. >+ * It's a ususal thing on serial to lose characters, isn't it? >+ * Neener, neener! Actually, it's probably an echo loop anyway. >+ * Only happens when getty starts talking to Visor. >+ */ >+ if (++rate % 1000 < 5) >+ err("too much data (%d)", count); >+ job->len = POST_BSIZE; >+ } >+ memcpy(job->buff, buf, job->len); >+ >+ spin_lock_irqsave(&post_lock, flags); >+ list_add_tail(&job->link, &post_list); >+ serial->ref++; /* Protect the port->sem from kfree() */ >+ schedule_task(&post_task); >+ spin_unlock_irqrestore(&post_lock, flags); >+ >+ return count; >+} >+ > static int serial_write_room (struct tty_struct *tty) > { > struct usb_serial_port *port = (struct usb_serial_port *) tty->driver_data; >@@ -620,6 +738,9 @@ > if (!serial) > return -ENODEV; > >+ if (in_interrupt()) >+ return POST_BSIZE; >+ > down (&port->sem); > > dbg("%s - port %d", __FUNCTION__, port->number); >@@ -1128,6 +1249,7 @@ > int num_ports; > int max_endpoints; > const struct usb_device_id *id_pattern = NULL; >+ unsigned long flags; > > /* loop through our list of known serial converters, and see if this > device matches. */ >@@ -1338,11 +1460,15 @@ > init_MUTEX (&port->sem); > } > >+ spin_lock_irqsave(&post_lock, flags); >+ serial->ref = 1; >+ spin_unlock_irqrestore(&post_lock, flags); >+ > /* if this device type has a startup function, call it */ > if (type->startup) { > i = type->startup (serial); > if (i < 0) >- goto probe_error; >+ goto startup_error; > if (i > 0) > return serial; > } >@@ -1357,6 +1483,12 @@ > return serial; /* success */ > > >+startup_error: >+ spin_lock_irqsave(&post_lock, flags); >+ if (serial->ref != 1) { >+ err("bug in component startup: ref %d\n", serial->ref); >+ } >+ spin_unlock_irqrestore(&post_lock, flags); > probe_error: > for (i = 0; i < num_bulk_in; ++i) { > port = &serial->port[i]; >@@ -1392,6 +1524,7 @@ > { > struct usb_serial *serial = (struct usb_serial *) ptr; > struct usb_serial_port *port; >+ unsigned long flags; > int i; > > dbg ("%s", __FUNCTION__); >@@ -1452,7 +1585,10 @@ > return_serial (serial); > > /* free up any memory that we allocated */ >- kfree (serial); >+ spin_lock_irqsave(&post_lock, flags); >+ if (--serial->ref == 0) >+ kfree(serial); >+ spin_unlock_irqrestore(&post_lock, flags); > > } else { > info("device disconnected"); >@@ -1504,6 +1640,7 @@ > for (i = 0; i < SERIAL_TTY_MINORS; ++i) { > serial_table[i] = NULL; > } >+ post_task.routine = post_helper; > > /* register the tty driver */ > serial_tty_driver.init_termios = tty_std_termios; >diff -ur linux-2.4.20-20.7.5/drivers/usb/serial/usb-serial.h linux-2.4.20-20.7.5-u1/drivers/usb/serial/usb-serial.h >--- linux-2.4.20-20.7.5/drivers/usb/serial/usb-serial.h 2002-11-28 18:53:15.000000000 -0500 >+++ linux-2.4.20-20.7.5-u1/drivers/usb/serial/usb-serial.h 2003-11-17 22:32:55.000000000 -0500 >@@ -151,6 +151,9 @@ > __u16 product; > struct usb_serial_port port[MAX_NUM_PORTS]; > void * private; >+#ifndef __GENKSYMS__ >+ int ref; >+#endif > }; > >
You cannot view the attachment while viewing its details because your browser does not support IFRAMEs.
View the attachment on a separate page
.
View Attachment As Diff
View Attachment As Raw
Actions:
View
|
Diff
Attachments on
bug 49600
:
30449
|
30450
|
30451
|
30452
|
30453
|
30454
|
30455
|
30456
|
30457