public inbox for linux-kernel@vger.kernel.org
 help / color / mirror / Atom feed
* [GIT PATCH] USB bugfixes and a PCI one too for 2.6.12-rc6
@ 2005-06-09 16:43 Greg KH
  2005-06-09 16:44 ` [PATCH] PCI Hotplug: fix CPCI reference counting bug Greg KH
  2005-06-09 17:49 ` [GIT PATCH] USB bugfixes and a PCI one too for 2.6.12-rc6 Linus Torvalds
  0 siblings, 2 replies; 7+ messages in thread
From: Greg KH @ 2005-06-09 16:43 UTC (permalink / raw)
  To: Linus Torvalds, Andrew Morton; +Cc: linux-kernel, linux-usb-devel

Here are some two USB patches and one PCI Hotplug patch for the
2.6.12-rc6 tree.  They are all bugfixes.  I've put them all in one repo
to make it easier for you to pull from :)

Please pull from:
	rsync://rsync.kernel.org/pub/scm/linux/kernel/git/gregkh/usb-2.6.git/

Full patches will be sent to the linux-usb-devel and linux-kernel
mailing lists, if anyone wants to see them.

thanks,

greg k-h

 drivers/block/ub.c                      |   10 -
 drivers/pci/hotplug/cpci_hotplug_core.c |    4 
 drivers/pci/hotplug/cpci_hotplug_pci.c  |   10 +
 drivers/usb/serial/ftdi_sio.c           |  236 ++++++++++++++++++++++++--------
 4 files changed, 198 insertions(+), 62 deletions(-)
-------------

Ian Abbott:
  USB: ftdi_sio: avoid losing received data in tty-ldisc

Pete Zaitcev:
  USB: fix ub issues

Scott Murray:
  PCI Hotplug: fix CPCI reference counting bug



^ permalink raw reply	[flat|nested] 7+ messages in thread

* [PATCH] USB: fix ub issues
  2005-06-09 16:44 ` [PATCH] PCI Hotplug: fix CPCI reference counting bug Greg KH
@ 2005-06-09 16:44   ` Greg KH
  2005-06-09 16:44     ` [PATCH] USB: ftdi_sio: avoid losing received data in tty-ldisc Greg KH
  2005-06-09 17:07     ` [PATCH] USB: fix ub issues Greg KH
  0 siblings, 2 replies; 7+ messages in thread
From: Greg KH @ 2005-06-09 16:44 UTC (permalink / raw)
  To: linux-kernel, linux-usb-devel; +Cc: zaitcev

[PATCH] USB: fix ub issues

This smoothes two imperfections:
- Increase number of LUNs per device from 4 to 9. The best solution
  would be to remove this limit altogether, but that has to wait until
  the time when more than 26 hosts are allowed.
- Replace mdelay with msleep in a probing routine.

Signed-off-by: Pete Zaitcev <zaitcev@yahoo.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>

---
commit 9f793d2c77ec5818679e4747c554d9333cecf476
tree 47904d2099435d4527432479e869311be7c6515b
parent 03e49d40ea3436cae0fe43708f11584130ee4a0c
author Pete Zaitcev <zaitcev@redhat.com> Mon, 06 Jun 2005 13:54:59 -0700
committer Greg Kroah-Hartman <gregkh@suse.de> Thu, 09 Jun 2005 01:38:11 -0700

 drivers/block/ub.c |    4 ++--
 1 files changed, 2 insertions(+), 2 deletions(-)

diff --git a/drivers/block/ub.c b/drivers/block/ub.c
--- a/drivers/block/ub.c
+++ b/drivers/block/ub.c
@@ -51,7 +51,7 @@
  * This many LUNs per USB device.
  * Every one of them takes a host, see UB_MAX_HOSTS.
  */
-#define UB_MAX_LUNS   4
+#define UB_MAX_LUNS   9
 
 /*
  */
@@ -2100,7 +2100,7 @@ static int ub_probe(struct usb_interface
 			nluns = rc;
 			break;
 		}
-		mdelay(100);
+		msleep(100);
 	}
 
 	for (i = 0; i < nluns; i++) {
zaitcev@redhat.com
[PATCH] USB: fix ub issues
[PATCH] USB: fix ub issues

This smoothes two imperfections:
- Increase number of LUNs per device from 4 to 9. The best solution
  would be to remove this limit altogether, but that has to wait until
  the time when more than 26 hosts are allowed.
- Replace mdelay with msleep in a probing routine.

Signed-off-by: Pete Zaitcev <zaitcev@yahoo.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>

---
commit 9f793d2c77ec5818679e4747c554d9333cecf476
tree 47904d2099435d4527432479e869311be7c6515b
parent 03e49d40ea3436cae0fe43708f11584130ee4a0c
author Pete Zaitcev <zaitcev@redhat.com> Mon, 06 Jun 2005 13:54:59 -0700
committer Greg Kroah-Hartman <gregkh@suse.de> Thu, 09 Jun 2005 01:38:11 -0700

 drivers/block/ub.c |    4 ++--
 1 files changed, 2 insertions(+), 2 deletions(-)

diff --git a/drivers/block/ub.c b/drivers/block/ub.c
--- a/drivers/block/ub.c
+++ b/drivers/block/ub.c
@@ -51,7 +51,7 @@
  * This many LUNs per USB device.
  * Every one of them takes a host, see UB_MAX_HOSTS.
  */
-#define UB_MAX_LUNS   4
+#define UB_MAX_LUNS   9
 
 /*
  */
@@ -2100,7 +2100,7 @@ static int ub_probe(struct usb_interface
 			nluns = rc;
 			break;
 		}
-		mdelay(100);
+		msleep(100);
 	}
 
 	for (i = 0; i < nluns; i++) {


^ permalink raw reply	[flat|nested] 7+ messages in thread

* [PATCH] PCI Hotplug: fix CPCI reference counting bug
  2005-06-09 16:43 [GIT PATCH] USB bugfixes and a PCI one too for 2.6.12-rc6 Greg KH
@ 2005-06-09 16:44 ` Greg KH
  2005-06-09 16:44   ` [PATCH] USB: fix ub issues Greg KH
  2005-06-09 17:49 ` [GIT PATCH] USB bugfixes and a PCI one too for 2.6.12-rc6 Linus Torvalds
  1 sibling, 1 reply; 7+ messages in thread
From: Greg KH @ 2005-06-09 16:44 UTC (permalink / raw)
  To: linux-kernel, linux-usb-devel; +Cc: scottm

[PATCH] PCI Hotplug: fix CPCI reference counting bug

Here's a patch that fixes up the pci_dev refcounting in the CPCI code.
I've done some testing against it and it seems fine here.

Signed-off-by: Scott Murray <scottm@somanetworks.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>

---
commit 03e49d40ea3436cae0fe43708f11584130ee4a0c
tree acaa11b11c0ff1d4c9f743c0d8df2bc5a865a440
parent 5273a00d9c763108397658d440618f7ac3e40f83
author Scott Murray <scottm@somanetworks.com> Mon, 06 Jun 2005 15:48:04 -0400
committer Greg Kroah-Hartman <gregkh@suse.de> Thu, 09 Jun 2005 01:37:59 -0700

 drivers/pci/hotplug/cpci_hotplug_core.c |    2 ++
 drivers/pci/hotplug/cpci_hotplug_pci.c  |    5 ++++-
 2 files changed, 6 insertions(+), 1 deletions(-)

diff --git a/drivers/pci/hotplug/cpci_hotplug_core.c b/drivers/pci/hotplug/cpci_hotplug_core.c
--- a/drivers/pci/hotplug/cpci_hotplug_core.c
+++ b/drivers/pci/hotplug/cpci_hotplug_core.c
@@ -217,6 +217,8 @@ static void release_slot(struct hotplug_
 	kfree(slot->hotplug_slot->info);
 	kfree(slot->hotplug_slot->name);
 	kfree(slot->hotplug_slot);
+	if (slot->dev)
+		pci_dev_put(slot->dev);
 	kfree(slot);
 }
 
diff --git a/drivers/pci/hotplug/cpci_hotplug_pci.c b/drivers/pci/hotplug/cpci_hotplug_pci.c
--- a/drivers/pci/hotplug/cpci_hotplug_pci.c
+++ b/drivers/pci/hotplug/cpci_hotplug_pci.c
@@ -315,9 +315,12 @@ int cpci_unconfigure_slot(struct slot* s
 				    PCI_DEVFN(PCI_SLOT(slot->devfn), i));
 		if (dev) {
 			pci_remove_bus_device(dev);
-			slot->dev = NULL;
+			pci_dev_put(dev);
 		}
 	}
+	pci_dev_put(slot->dev);
+	slot->dev = NULL;
+
 	dbg("%s - exit", __FUNCTION__);
 	return 0;
 }
scottm@somanetworks.com
[PATCH] PCI Hotplug: fix CPCI reference counting bug
[PATCH] PCI Hotplug: fix CPCI reference counting bug

Here's a patch that fixes up the pci_dev refcounting in the CPCI code.
I've done some testing against it and it seems fine here.

Signed-off-by: Scott Murray <scottm@somanetworks.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>

---
commit 03e49d40ea3436cae0fe43708f11584130ee4a0c
tree acaa11b11c0ff1d4c9f743c0d8df2bc5a865a440
parent 5273a00d9c763108397658d440618f7ac3e40f83
author Scott Murray <scottm@somanetworks.com> Mon, 06 Jun 2005 15:48:04 -0400
committer Greg Kroah-Hartman <gregkh@suse.de> Thu, 09 Jun 2005 01:37:59 -0700

 drivers/pci/hotplug/cpci_hotplug_core.c |    2 ++
 drivers/pci/hotplug/cpci_hotplug_pci.c  |    5 ++++-
 2 files changed, 6 insertions(+), 1 deletions(-)

diff --git a/drivers/pci/hotplug/cpci_hotplug_core.c b/drivers/pci/hotplug/cpci_hotplug_core.c
--- a/drivers/pci/hotplug/cpci_hotplug_core.c
+++ b/drivers/pci/hotplug/cpci_hotplug_core.c
@@ -217,6 +217,8 @@ static void release_slot(struct hotplug_
 	kfree(slot->hotplug_slot->info);
 	kfree(slot->hotplug_slot->name);
 	kfree(slot->hotplug_slot);
+	if (slot->dev)
+		pci_dev_put(slot->dev);
 	kfree(slot);
 }
 
diff --git a/drivers/pci/hotplug/cpci_hotplug_pci.c b/drivers/pci/hotplug/cpci_hotplug_pci.c
--- a/drivers/pci/hotplug/cpci_hotplug_pci.c
+++ b/drivers/pci/hotplug/cpci_hotplug_pci.c
@@ -315,9 +315,12 @@ int cpci_unconfigure_slot(struct slot* s
 				    PCI_DEVFN(PCI_SLOT(slot->devfn), i));
 		if (dev) {
 			pci_remove_bus_device(dev);
-			slot->dev = NULL;
+			pci_dev_put(dev);
 		}
 	}
+	pci_dev_put(slot->dev);
+	slot->dev = NULL;
+
 	dbg("%s - exit", __FUNCTION__);
 	return 0;
 }


^ permalink raw reply	[flat|nested] 7+ messages in thread

* [PATCH] USB: ftdi_sio: avoid losing received data in tty-ldisc
  2005-06-09 16:44   ` [PATCH] USB: fix ub issues Greg KH
@ 2005-06-09 16:44     ` Greg KH
  2005-06-09 17:07     ` [PATCH] USB: fix ub issues Greg KH
  1 sibling, 0 replies; 7+ messages in thread
From: Greg KH @ 2005-06-09 16:44 UTC (permalink / raw)
  To: linux-kernel, linux-usb-devel; +Cc: abbotti

[PATCH] USB: ftdi_sio: avoid losing received data in tty-ldisc

ftdi_sio: Avoid losing bytes at tty-ldisc.

This patch was originally developed by Daniel Smertnig.  I
(Ian Abbott) made a few changes.  It has been tested by both
Daniel and I, at least for raw, non-canonical receive data
processing.

Here is Daniel's original description of the patch:

===
During a project in which I was using a FTDI 232BM to
transmit data at relative high speeds (625kBit/s), I
noticed a problem where data was lost even if flow
control was enabled: The FTDI-Driver receives 512 Bytes
of data over USB at a time, which consists of 8 64-Byte
packets. Subtracting the 2 bytes of status information
included in each packet this gives 496 "real" data
bytes per read.

This data is passed (indirectly, via the flip buffers)
to the tty line discipline which takes care of
throttling when there the free buffer space reaches
TTY_THRESHOLD_THROTTLE (128). Because the FTDI driver
processes up to 496 bytes at a time, throttling won't
happen in time and the line discipline will discard the
remaining bytes.

To avoid this the patch passes data in 62-byte blocks
to the tty layer and checks the available space in the
ldisc-buffers. If there isn't enough free space,
processing the rest of the data is delayed using a
workqueue.

Note: The original problem should be easily
reproducible with a userspace program which does slow &
small reads.
===

Signed-off-by: Ian Abbott <abbotti@mev.co.uk>
Signed-off-by: Daniel Smertnig <daniel.smertnig@gmail.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>

---
commit 76854ceac3ef3408ab9a50a2521147fb14779f58
tree 130700c6871e73269bfad0b9f0439d51e0c353a3
parent 9f793d2c77ec5818679e4747c554d9333cecf476
author Ian Abbott <abbotti@mev.co.uk> Thu, 02 Jun 2005 10:34:11 +0100
committer Greg Kroah-Hartman <gregkh@suse.de> Thu, 09 Jun 2005 01:38:15 -0700

 drivers/usb/serial/ftdi_sio.c |  118 ++++++++++++++++++++++++++++++++---------
 1 files changed, 91 insertions(+), 27 deletions(-)

diff --git a/drivers/usb/serial/ftdi_sio.c b/drivers/usb/serial/ftdi_sio.c
--- a/drivers/usb/serial/ftdi_sio.c
+++ b/drivers/usb/serial/ftdi_sio.c
@@ -264,7 +264,7 @@
 /*
  * Version Information
  */
-#define DRIVER_VERSION "v1.4.1"
+#define DRIVER_VERSION "v1.4.2"
 #define DRIVER_AUTHOR "Greg Kroah-Hartman <greg@kroah.com>, Bill Ryder <bryder@sgi.com>, Kuba Ober <kuba@mareimbrium.org>"
 #define DRIVER_DESC "USB FTDI Serial Converters Driver"
 
@@ -687,6 +687,8 @@ struct ftdi_private {
  	char prev_status, diff_status;        /* Used for TIOCMIWAIT */
 	__u8 rx_flags;		/* receive state flags (throttling) */
 	spinlock_t rx_lock;	/* spinlock for receive state */
+	struct work_struct rx_work;
+	int rx_processed;
 
 	__u16 interface;	/* FT2232C port interface (0 for FT232/245) */
 
@@ -717,7 +719,7 @@ static int  ftdi_write_room		(struct usb
 static int  ftdi_chars_in_buffer	(struct usb_serial_port *port);
 static void ftdi_write_bulk_callback	(struct urb *urb, struct pt_regs *regs);
 static void ftdi_read_bulk_callback	(struct urb *urb, struct pt_regs *regs);
-static void ftdi_process_read		(struct usb_serial_port *port);
+static void ftdi_process_read		(void *param);
 static void ftdi_set_termios		(struct usb_serial_port *port, struct termios * old);
 static int  ftdi_tiocmget               (struct usb_serial_port *port, struct file *file);
 static int  ftdi_tiocmset		(struct usb_serial_port *port, struct file * file, unsigned int set, unsigned int clear);
@@ -1387,6 +1389,8 @@ static int ftdi_common_startup (struct u
 		port->read_urb->transfer_buffer_length = BUFSZ;
 	}
 
+	INIT_WORK(&priv->rx_work, ftdi_process_read, port);
+
 	/* Free port's existing write urb and transfer buffer. */
 	if (port->write_urb) {
 		usb_free_urb (port->write_urb);
@@ -1617,6 +1621,7 @@ static int  ftdi_open (struct usb_serial
 	spin_unlock_irqrestore(&priv->rx_lock, flags);
 
 	/* Start reading from the device */
+	priv->rx_processed = 0;
 	usb_fill_bulk_urb(port->read_urb, dev,
 		      usb_rcvbulkpipe(dev, port->bulk_in_endpointAddress),
 		      port->read_urb->transfer_buffer, port->read_urb->transfer_buffer_length,
@@ -1667,6 +1672,10 @@ static void ftdi_close (struct usb_seria
 			err("Error from RTS LOW urb");
 		}
 	} /* Note change no line if hupcl is off */
+
+	/* cancel any scheduled reading */
+	cancel_delayed_work(&priv->rx_work);
+	flush_scheduled_work();
 	
 	/* shutdown our bulk read */
 	if (port->read_urb)
@@ -1862,23 +1871,14 @@ static void ftdi_read_bulk_callback (str
 		return;
 	}
 
-	/* If throttled, delay receive processing until unthrottled. */
-	spin_lock(&priv->rx_lock);
-	if (priv->rx_flags & THROTTLED) {
-		dbg("Deferring read urb processing until unthrottled");
-		priv->rx_flags |= ACTUALLY_THROTTLED;
-		spin_unlock(&priv->rx_lock);
-		return;
-	}
-	spin_unlock(&priv->rx_lock);
-
 	ftdi_process_read(port);
 
 } /* ftdi_read_bulk_callback */
 
 
-static void ftdi_process_read (struct usb_serial_port *port)
+static void ftdi_process_read (void *param)
 { /* ftdi_process_read */
+	struct usb_serial_port *port = (struct usb_serial_port*)param;
 	struct urb *urb;
 	struct tty_struct *tty;
 	struct ftdi_private *priv;
@@ -1889,6 +1889,7 @@ static void ftdi_process_read (struct us
 	int result;
 	int need_flip;
 	int packet_offset;
+	unsigned long flags;
 
 	dbg("%s - port %d", __FUNCTION__, port->number);
 
@@ -1915,12 +1916,18 @@ static void ftdi_process_read (struct us
 
 	data = urb->transfer_buffer;
 
-        /* The first two bytes of every read packet are status */
-	if (urb->actual_length > 2) {
-		usb_serial_debug_data(debug, &port->dev, __FUNCTION__, urb->actual_length, data);
+	if (priv->rx_processed) {
+		dbg("%s - already processed: %d bytes, %d remain", __FUNCTION__,
+				priv->rx_processed,
+				urb->actual_length - priv->rx_processed);
 	} else {
-                dbg("Status only: %03oo %03oo",data[0],data[1]);
-        }
+		/* The first two bytes of every read packet are status */
+		if (urb->actual_length > 2) {
+			usb_serial_debug_data(debug, &port->dev, __FUNCTION__, urb->actual_length, data);
+		} else {
+			dbg("Status only: %03oo %03oo",data[0],data[1]);
+		}
+	}
 
 
 	/* TO DO -- check for hung up line and handle appropriately: */
@@ -1929,8 +1936,12 @@ static void ftdi_process_read (struct us
 	/* if CD is dropped and the line is not CLOCAL then we should hangup */
 
 	need_flip = 0;
-	for (packet_offset=0; packet_offset < urb->actual_length; packet_offset += PKTSZ) {
+	for (packet_offset = priv->rx_processed; packet_offset < urb->actual_length; packet_offset += PKTSZ) {
+		int length;
+
 		/* Compare new line status to the old one, signal if different */
+		/* N.B. packet may be processed more than once, but differences
+		 * are only processed once.  */
 		if (priv != NULL) {
 			char new_status = data[packet_offset+0] & FTDI_STATUS_B0_MASK;
 			if (new_status != priv->prev_status) {
@@ -1940,6 +1951,35 @@ static void ftdi_process_read (struct us
 			}
 		}
 
+		length = min(PKTSZ, urb->actual_length-packet_offset)-2;
+		if (length < 0) {
+			err("%s - bad packet length: %d", __FUNCTION__, length+2);
+			length = 0;
+		}
+
+		/* have to make sure we don't overflow the buffer
+		   with tty_insert_flip_char's */
+		if (tty->flip.count+length > TTY_FLIPBUF_SIZE) {
+			tty_flip_buffer_push(tty);
+			need_flip = 0;
+
+			if (tty->flip.count != 0) {
+				/* flip didn't work, this happens when ftdi_process_read() is
+				 * called from ftdi_unthrottle, because TTY_DONT_FLIP is set */
+				dbg("%s - flip buffer push failed", __FUNCTION__);
+				break;
+			}
+		}
+		if (priv->rx_flags & THROTTLED) {
+			dbg("%s - throttled", __FUNCTION__);
+			break;
+		}
+		if (tty->ldisc.receive_room(tty)-tty->flip.count < length) {
+			/* break out & wait for throttling/unthrottling to happen */
+			dbg("%s - receive room low", __FUNCTION__);
+			break;
+		}
+
 		/* Handle errors and break */
 		error_flag = TTY_NORMAL;
 		/* Although the device uses a bitmask and hence can have multiple */
@@ -1962,13 +2002,8 @@ static void ftdi_process_read (struct us
 			error_flag = TTY_FRAME;
 			dbg("FRAMING error");
 		}
-		if (urb->actual_length > packet_offset + 2) {
-			for (i = 2; (i < PKTSZ) && ((i+packet_offset) < urb->actual_length); ++i) {
-				/* have to make sure we don't overflow the buffer
-				  with tty_insert_flip_char's */
-				if(tty->flip.count >= TTY_FLIPBUF_SIZE) {
-					tty_flip_buffer_push(tty);
-				}
+		if (length > 0) {
+			for (i = 2; i < length+2; i++) {
 				/* Note that the error flag is duplicated for 
 				   every character received since we don't know
 				   which character it applied to */
@@ -2005,6 +2040,35 @@ static void ftdi_process_read (struct us
 		tty_flip_buffer_push(tty);
 	}
 
+	if (packet_offset < urb->actual_length) {
+		/* not completely processed - record progress */
+		priv->rx_processed = packet_offset;
+		dbg("%s - incomplete, %d bytes processed, %d remain",
+				__FUNCTION__, packet_offset,
+				urb->actual_length - packet_offset);
+		/* check if we were throttled while processing */
+		spin_lock_irqsave(&priv->rx_lock, flags);
+		if (priv->rx_flags & THROTTLED) {
+			priv->rx_flags |= ACTUALLY_THROTTLED;
+			spin_unlock_irqrestore(&priv->rx_lock, flags);
+			dbg("%s - deferring remainder until unthrottled",
+					__FUNCTION__);
+			return;
+		}
+		spin_unlock_irqrestore(&priv->rx_lock, flags);
+		/* if the port is closed stop trying to read */
+		if (port->open_count > 0){
+			/* delay processing of remainder */
+			schedule_delayed_work(&priv->rx_work, 1);
+		} else {
+			dbg("%s - port is closed", __FUNCTION__);
+		}
+		return;
+	}
+
+	/* urb is completely processed */
+	priv->rx_processed = 0;
+
 	/* if the port is closed stop trying to read */
 	if (port->open_count > 0){
 		/* Continue trying to always read  */
@@ -2444,7 +2508,7 @@ static void ftdi_unthrottle (struct usb_
 	spin_unlock_irqrestore(&priv->rx_lock, flags);
 
 	if (actually_throttled)
-		ftdi_process_read(port);
+		schedule_work(&priv->rx_work);
 }
 
 static int __init ftdi_init (void)
abbotti@mev.co.uk
[PATCH] USB: ftdi_sio: avoid losing received data in tty-ldisc
[PATCH] USB: ftdi_sio: avoid losing received data in tty-ldisc

ftdi_sio: Avoid losing bytes at tty-ldisc.

This patch was originally developed by Daniel Smertnig.  I
(Ian Abbott) made a few changes.  It has been tested by both
Daniel and I, at least for raw, non-canonical receive data
processing.

Here is Daniel's original description of the patch:

===
During a project in which I was using a FTDI 232BM to
transmit data at relative high speeds (625kBit/s), I
noticed a problem where data was lost even if flow
control was enabled: The FTDI-Driver receives 512 Bytes
of data over USB at a time, which consists of 8 64-Byte
packets. Subtracting the 2 bytes of status information
included in each packet this gives 496 "real" data
bytes per read.

This data is passed (indirectly, via the flip buffers)
to the tty line discipline which takes care of
throttling when there the free buffer space reaches
TTY_THRESHOLD_THROTTLE (128). Because the FTDI driver
processes up to 496 bytes at a time, throttling won't
happen in time and the line discipline will discard the
remaining bytes.

To avoid this the patch passes data in 62-byte blocks
to the tty layer and checks the available space in the
ldisc-buffers. If there isn't enough free space,
processing the rest of the data is delayed using a
workqueue.

Note: The original problem should be easily
reproducible with a userspace program which does slow &
small reads.
===

Signed-off-by: Ian Abbott <abbotti@mev.co.uk>
Signed-off-by: Daniel Smertnig <daniel.smertnig@gmail.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>

---
commit 76854ceac3ef3408ab9a50a2521147fb14779f58
tree 130700c6871e73269bfad0b9f0439d51e0c353a3
parent 9f793d2c77ec5818679e4747c554d9333cecf476
author Ian Abbott <abbotti@mev.co.uk> Thu, 02 Jun 2005 10:34:11 +0100
committer Greg Kroah-Hartman <gregkh@suse.de> Thu, 09 Jun 2005 01:38:15 -0700

 drivers/usb/serial/ftdi_sio.c |  118 ++++++++++++++++++++++++++++++++---------
 1 files changed, 91 insertions(+), 27 deletions(-)

diff --git a/drivers/usb/serial/ftdi_sio.c b/drivers/usb/serial/ftdi_sio.c
--- a/drivers/usb/serial/ftdi_sio.c
+++ b/drivers/usb/serial/ftdi_sio.c
@@ -264,7 +264,7 @@
 /*
  * Version Information
  */
-#define DRIVER_VERSION "v1.4.1"
+#define DRIVER_VERSION "v1.4.2"
 #define DRIVER_AUTHOR "Greg Kroah-Hartman <greg@kroah.com>, Bill Ryder <bryder@sgi.com>, Kuba Ober <kuba@mareimbrium.org>"
 #define DRIVER_DESC "USB FTDI Serial Converters Driver"
 
@@ -687,6 +687,8 @@ struct ftdi_private {
  	char prev_status, diff_status;        /* Used for TIOCMIWAIT */
 	__u8 rx_flags;		/* receive state flags (throttling) */
 	spinlock_t rx_lock;	/* spinlock for receive state */
+	struct work_struct rx_work;
+	int rx_processed;
 
 	__u16 interface;	/* FT2232C port interface (0 for FT232/245) */
 
@@ -717,7 +719,7 @@ static int  ftdi_write_room		(struct usb
 static int  ftdi_chars_in_buffer	(struct usb_serial_port *port);
 static void ftdi_write_bulk_callback	(struct urb *urb, struct pt_regs *regs);
 static void ftdi_read_bulk_callback	(struct urb *urb, struct pt_regs *regs);
-static void ftdi_process_read		(struct usb_serial_port *port);
+static void ftdi_process_read		(void *param);
 static void ftdi_set_termios		(struct usb_serial_port *port, struct termios * old);
 static int  ftdi_tiocmget               (struct usb_serial_port *port, struct file *file);
 static int  ftdi_tiocmset		(struct usb_serial_port *port, struct file * file, unsigned int set, unsigned int clear);
@@ -1387,6 +1389,8 @@ static int ftdi_common_startup (struct u
 		port->read_urb->transfer_buffer_length = BUFSZ;
 	}
 
+	INIT_WORK(&priv->rx_work, ftdi_process_read, port);
+
 	/* Free port's existing write urb and transfer buffer. */
 	if (port->write_urb) {
 		usb_free_urb (port->write_urb);
@@ -1617,6 +1621,7 @@ static int  ftdi_open (struct usb_serial
 	spin_unlock_irqrestore(&priv->rx_lock, flags);
 
 	/* Start reading from the device */
+	priv->rx_processed = 0;
 	usb_fill_bulk_urb(port->read_urb, dev,
 		      usb_rcvbulkpipe(dev, port->bulk_in_endpointAddress),
 		      port->read_urb->transfer_buffer, port->read_urb->transfer_buffer_length,
@@ -1667,6 +1672,10 @@ static void ftdi_close (struct usb_seria
 			err("Error from RTS LOW urb");
 		}
 	} /* Note change no line if hupcl is off */
+
+	/* cancel any scheduled reading */
+	cancel_delayed_work(&priv->rx_work);
+	flush_scheduled_work();
 	
 	/* shutdown our bulk read */
 	if (port->read_urb)
@@ -1862,23 +1871,14 @@ static void ftdi_read_bulk_callback (str
 		return;
 	}
 
-	/* If throttled, delay receive processing until unthrottled. */
-	spin_lock(&priv->rx_lock);
-	if (priv->rx_flags & THROTTLED) {
-		dbg("Deferring read urb processing until unthrottled");
-		priv->rx_flags |= ACTUALLY_THROTTLED;
-		spin_unlock(&priv->rx_lock);
-		return;
-	}
-	spin_unlock(&priv->rx_lock);
-
 	ftdi_process_read(port);
 
 } /* ftdi_read_bulk_callback */
 
 
-static void ftdi_process_read (struct usb_serial_port *port)
+static void ftdi_process_read (void *param)
 { /* ftdi_process_read */
+	struct usb_serial_port *port = (struct usb_serial_port*)param;
 	struct urb *urb;
 	struct tty_struct *tty;
 	struct ftdi_private *priv;
@@ -1889,6 +1889,7 @@ static void ftdi_process_read (struct us
 	int result;
 	int need_flip;
 	int packet_offset;
+	unsigned long flags;
 
 	dbg("%s - port %d", __FUNCTION__, port->number);
 
@@ -1915,12 +1916,18 @@ static void ftdi_process_read (struct us
 
 	data = urb->transfer_buffer;
 
-        /* The first two bytes of every read packet are status */
-	if (urb->actual_length > 2) {
-		usb_serial_debug_data(debug, &port->dev, __FUNCTION__, urb->actual_length, data);
+	if (priv->rx_processed) {
+		dbg("%s - already processed: %d bytes, %d remain", __FUNCTION__,
+				priv->rx_processed,
+				urb->actual_length - priv->rx_processed);
 	} else {
-                dbg("Status only: %03oo %03oo",data[0],data[1]);
-        }
+		/* The first two bytes of every read packet are status */
+		if (urb->actual_length > 2) {
+			usb_serial_debug_data(debug, &port->dev, __FUNCTION__, urb->actual_length, data);
+		} else {
+			dbg("Status only: %03oo %03oo",data[0],data[1]);
+		}
+	}
 
 
 	/* TO DO -- check for hung up line and handle appropriately: */
@@ -1929,8 +1936,12 @@ static void ftdi_process_read (struct us
 	/* if CD is dropped and the line is not CLOCAL then we should hangup */
 
 	need_flip = 0;
-	for (packet_offset=0; packet_offset < urb->actual_length; packet_offset += PKTSZ) {
+	for (packet_offset = priv->rx_processed; packet_offset < urb->actual_length; packet_offset += PKTSZ) {
+		int length;
+
 		/* Compare new line status to the old one, signal if different */
+		/* N.B. packet may be processed more than once, but differences
+		 * are only processed once.  */
 		if (priv != NULL) {
 			char new_status = data[packet_offset+0] & FTDI_STATUS_B0_MASK;
 			if (new_status != priv->prev_status) {
@@ -1940,6 +1951,35 @@ static void ftdi_process_read (struct us
 			}
 		}
 
+		length = min(PKTSZ, urb->actual_length-packet_offset)-2;
+		if (length < 0) {
+			err("%s - bad packet length: %d", __FUNCTION__, length+2);
+			length = 0;
+		}
+
+		/* have to make sure we don't overflow the buffer
+		   with tty_insert_flip_char's */
+		if (tty->flip.count+length > TTY_FLIPBUF_SIZE) {
+			tty_flip_buffer_push(tty);
+			need_flip = 0;
+
+			if (tty->flip.count != 0) {
+				/* flip didn't work, this happens when ftdi_process_read() is
+				 * called from ftdi_unthrottle, because TTY_DONT_FLIP is set */
+				dbg("%s - flip buffer push failed", __FUNCTION__);
+				break;
+			}
+		}
+		if (priv->rx_flags & THROTTLED) {
+			dbg("%s - throttled", __FUNCTION__);
+			break;
+		}
+		if (tty->ldisc.receive_room(tty)-tty->flip.count < length) {
+			/* break out & wait for throttling/unthrottling to happen */
+			dbg("%s - receive room low", __FUNCTION__);
+			break;
+		}
+
 		/* Handle errors and break */
 		error_flag = TTY_NORMAL;
 		/* Although the device uses a bitmask and hence can have multiple */
@@ -1962,13 +2002,8 @@ static void ftdi_process_read (struct us
 			error_flag = TTY_FRAME;
 			dbg("FRAMING error");
 		}
-		if (urb->actual_length > packet_offset + 2) {
-			for (i = 2; (i < PKTSZ) && ((i+packet_offset) < urb->actual_length); ++i) {
-				/* have to make sure we don't overflow the buffer
-				  with tty_insert_flip_char's */
-				if(tty->flip.count >= TTY_FLIPBUF_SIZE) {
-					tty_flip_buffer_push(tty);
-				}
+		if (length > 0) {
+			for (i = 2; i < length+2; i++) {
 				/* Note that the error flag is duplicated for 
 				   every character received since we don't know
 				   which character it applied to */
@@ -2005,6 +2040,35 @@ static void ftdi_process_read (struct us
 		tty_flip_buffer_push(tty);
 	}
 
+	if (packet_offset < urb->actual_length) {
+		/* not completely processed - record progress */
+		priv->rx_processed = packet_offset;
+		dbg("%s - incomplete, %d bytes processed, %d remain",
+				__FUNCTION__, packet_offset,
+				urb->actual_length - packet_offset);
+		/* check if we were throttled while processing */
+		spin_lock_irqsave(&priv->rx_lock, flags);
+		if (priv->rx_flags & THROTTLED) {
+			priv->rx_flags |= ACTUALLY_THROTTLED;
+			spin_unlock_irqrestore(&priv->rx_lock, flags);
+			dbg("%s - deferring remainder until unthrottled",
+					__FUNCTION__);
+			return;
+		}
+		spin_unlock_irqrestore(&priv->rx_lock, flags);
+		/* if the port is closed stop trying to read */
+		if (port->open_count > 0){
+			/* delay processing of remainder */
+			schedule_delayed_work(&priv->rx_work, 1);
+		} else {
+			dbg("%s - port is closed", __FUNCTION__);
+		}
+		return;
+	}
+
+	/* urb is completely processed */
+	priv->rx_processed = 0;
+
 	/* if the port is closed stop trying to read */
 	if (port->open_count > 0){
 		/* Continue trying to always read  */
@@ -2444,7 +2508,7 @@ static void ftdi_unthrottle (struct usb_
 	spin_unlock_irqrestore(&priv->rx_lock, flags);
 
 	if (actually_throttled)
-		ftdi_process_read(port);
+		schedule_work(&priv->rx_work);
 }
 
 static int __init ftdi_init (void)


^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: [PATCH] USB: fix ub issues
  2005-06-09 16:44   ` [PATCH] USB: fix ub issues Greg KH
  2005-06-09 16:44     ` [PATCH] USB: ftdi_sio: avoid losing received data in tty-ldisc Greg KH
@ 2005-06-09 17:07     ` Greg KH
  1 sibling, 0 replies; 7+ messages in thread
From: Greg KH @ 2005-06-09 17:07 UTC (permalink / raw)
  To: linux-kernel, linux-usb-devel, zaitcev

On Thu, Jun 09, 2005 at 09:44:53AM -0700, Greg KH wrote:
> [PATCH] USB: fix ub issues

<snip>

> [PATCH] USB: fix ub issues

<snip>

Crap, my scripts went crazy again, due to changes in git (sure, blame
someone else...)  Sorry about the "double the patch" messages.

thanks,

greg k-h

^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: [GIT PATCH] USB bugfixes and a PCI one too for 2.6.12-rc6
  2005-06-09 16:43 [GIT PATCH] USB bugfixes and a PCI one too for 2.6.12-rc6 Greg KH
  2005-06-09 16:44 ` [PATCH] PCI Hotplug: fix CPCI reference counting bug Greg KH
@ 2005-06-09 17:49 ` Linus Torvalds
  2005-06-09 17:52   ` Greg KH
  1 sibling, 1 reply; 7+ messages in thread
From: Linus Torvalds @ 2005-06-09 17:49 UTC (permalink / raw)
  To: Greg KH; +Cc: Andrew Morton, linux-kernel, linux-usb-devel



On Thu, 9 Jun 2005, Greg KH wrote:
> 
> Please pull from:
> 	rsync://rsync.kernel.org/pub/scm/linux/kernel/git/gregkh/usb-2.6.git/
> 
>  drivers/block/ub.c                      |   10 -
>  drivers/pci/hotplug/cpci_hotplug_core.c |    4 
>  drivers/pci/hotplug/cpci_hotplug_pci.c  |   10 +
>  drivers/usb/serial/ftdi_sio.c           |  236 ++++++++++++++++++++++++--------
>  4 files changed, 198 insertions(+), 62 deletions(-)

Hmm.. I see the three commits you mention, but this doesn't match what I
get:

	 drivers/block/ub.c                      |    4 +
	 drivers/pci/hotplug/cpci_hotplug_core.c |    2 +
	 drivers/pci/hotplug/cpci_hotplug_pci.c  |    5 +
	 drivers/usb/serial/ftdi_sio.c           |  118 ++++++++++++++++++++++++-------
	 4 files changed, 99 insertions(+), 30 deletions(-)

whazzup?

		Linus

^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: [GIT PATCH] USB bugfixes and a PCI one too for 2.6.12-rc6
  2005-06-09 17:49 ` [GIT PATCH] USB bugfixes and a PCI one too for 2.6.12-rc6 Linus Torvalds
@ 2005-06-09 17:52   ` Greg KH
  0 siblings, 0 replies; 7+ messages in thread
From: Greg KH @ 2005-06-09 17:52 UTC (permalink / raw)
  To: Linus Torvalds; +Cc: Andrew Morton, linux-kernel, linux-usb-devel

On Thu, Jun 09, 2005 at 10:49:09AM -0700, Linus Torvalds wrote:
> 
> 
> On Thu, 9 Jun 2005, Greg KH wrote:
> > 
> > Please pull from:
> > 	rsync://rsync.kernel.org/pub/scm/linux/kernel/git/gregkh/usb-2.6.git/
> > 
> >  drivers/block/ub.c                      |   10 -
> >  drivers/pci/hotplug/cpci_hotplug_core.c |    4 
> >  drivers/pci/hotplug/cpci_hotplug_pci.c  |   10 +
> >  drivers/usb/serial/ftdi_sio.c           |  236 ++++++++++++++++++++++++--------
> >  4 files changed, 198 insertions(+), 62 deletions(-)
> 
> Hmm.. I see the three commits you mention, but this doesn't match what I
> get:
> 
> 	 drivers/block/ub.c                      |    4 +
> 	 drivers/pci/hotplug/cpci_hotplug_core.c |    2 +
> 	 drivers/pci/hotplug/cpci_hotplug_pci.c  |    5 +
> 	 drivers/usb/serial/ftdi_sio.c           |  118 ++++++++++++++++++++++++-------
> 	 4 files changed, 99 insertions(+), 30 deletions(-)
> 
> whazzup?

My scripts generated patches that were duplicates due to either something in my
scripts that messed up, or due to some way that the git commands changed from
the last time I checked.  Odds are it's my fault.  So it counted
everything twice.  Let me go generate the patches again...

Ok, here's what I get:

 drivers/block/ub.c                      |    4 -
 drivers/pci/hotplug/cpci_hotplug_core.c |    2 
 drivers/pci/hotplug/cpci_hotplug_pci.c  |    5 +
 drivers/usb/serial/ftdi_sio.c           |  118 ++++++++++++++++++++++++--------
 4 files changed, 99 insertions(+), 30 deletions(-)

So your merge is correct.  Thanks for verifying.

greg k-h

^ permalink raw reply	[flat|nested] 7+ messages in thread

end of thread, other threads:[~2005-06-09 17:52 UTC | newest]

Thread overview: 7+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2005-06-09 16:43 [GIT PATCH] USB bugfixes and a PCI one too for 2.6.12-rc6 Greg KH
2005-06-09 16:44 ` [PATCH] PCI Hotplug: fix CPCI reference counting bug Greg KH
2005-06-09 16:44   ` [PATCH] USB: fix ub issues Greg KH
2005-06-09 16:44     ` [PATCH] USB: ftdi_sio: avoid losing received data in tty-ldisc Greg KH
2005-06-09 17:07     ` [PATCH] USB: fix ub issues Greg KH
2005-06-09 17:49 ` [GIT PATCH] USB bugfixes and a PCI one too for 2.6.12-rc6 Linus Torvalds
2005-06-09 17:52   ` Greg KH

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox