All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH] Airprime driver improvements to allow full speed EvDO transfers
@ 2006-06-30  5:48 Andy Gay
  2006-06-30  7:10 ` Andrew Morton
                   ` (4 more replies)
  0 siblings, 5 replies; 40+ messages in thread
From: Andy Gay @ 2006-06-30  5:48 UTC (permalink / raw)
  To: Greg KH; +Cc: linux-kernel, linux-usb-devel


Adapted from an earlier patch by Greg KH <gregkh@suse.de>.
That patch added multiple read urbs and larger transfer buffers to allow
data transfers at full EvDO speed.

This version includes additional device IDs and fixes a memory leak in
the transfer buffer allocation.

Some (maybe all?) of the supported devices present multiple bulk endpoints,
the additional EPs can be used for control and status functions.
This version allocates 3 EPs by default, that can be changed using
the 'endpoints' module parameter.

Tested with Sierra Wireless EM5625 and MC5720 embedded modules.

Device ID (0x0c88, 0x17da) for the Kyocera Wireless KPC650/Passport
was added but is not yet tested.

Signed-off-by: Andy Gay <andy@andynet.net>

---
commit 3d1346863aac4b3c016acb409a3b9e6651af8f7a
tree f4359718b8550ce0d95b57ba1b5b0d902bf2ada8
parent 501b7c77de3e90519e95fd99e923bf9a29cd120d
author andy <andy@tahini.andynet.net> Fri, 30 Jun 2006 01:27:13 -0400
committer andy <andy@tahini.andynet.net> Fri, 30 Jun 2006 01:27:13 -0400

 drivers/usb/serial/airprime.c |  227 ++++++++++++++++++++++++++++++++++++++++-
 1 files changed, 222 insertions(+), 5 deletions(-)

diff --git a/drivers/usb/serial/airprime.c b/drivers/usb/serial/airprime.c
index 94b9ba0..5a18f77 100644
--- a/drivers/usb/serial/airprime.c
+++ b/drivers/usb/serial/airprime.c
@@ -1,7 +1,7 @@
 /*
  * AirPrime CDMA Wireless Serial USB driver
  *
- * Copyright (C) 2005 Greg Kroah-Hartman <gregkh@suse.de>
+ * Copyright (C) 2005-2006 Greg Kroah-Hartman <gregkh@suse.de>
  *
  *	This program is free software; you can redistribute it and/or
  *	modify it under the terms of the GNU General Public License version
@@ -11,26 +11,232 @@
 #include <linux/kernel.h>
 #include <linux/init.h>
 #include <linux/tty.h>
+#include <linux/tty_flip.h>
 #include <linux/module.h>
 #include <linux/usb.h>
 #include "usb-serial.h"
 
 static struct usb_device_id id_table [] = {
 	{ USB_DEVICE(0x0c88, 0x17da) }, /* Kyocera Wireless KPC650/Passport */
-	{ USB_DEVICE(0xf3d, 0x0112) },  /* AirPrime CDMA Wireless PC Card */
+	{ USB_DEVICE(0x0f3d, 0x0112) },	/* AirPrime CDMA Wireless PC Card */
 	{ USB_DEVICE(0x1410, 0x1110) }, /* Novatel Wireless Merlin CDMA */
+	{ USB_DEVICE(0x1199, 0x0017) }, /* Sierra Wireless EM5625 */
+	{ USB_DEVICE(0x1199, 0x0018) }, /* Sierra Wireless MC5720 */
 	{ USB_DEVICE(0x1199, 0x0112) }, /* Sierra Wireless Aircard 580 */
-	{ USB_DEVICE(0x1199, 0x0218) }, /* Sierra Wireless MC5720 */
 	{ },
 };
 MODULE_DEVICE_TABLE(usb, id_table);
+#define URB_TRANSFER_BUFFER_SIZE	4096
+#define NUM_READ_URBS			4
+#define NUM_WRITE_URBS			4
+#define NUM_BULK_EPS			3
+#define MAX_BULK_EPS			6
+
+/* if overridden by the user, then use their value for the size of the
+ * read and write urbs, and the number of endpoints */
+static int buffer_size = URB_TRANSFER_BUFFER_SIZE;
+static int endpoints = NUM_BULK_EPS;
+static int debug;
+struct airprime_private {
+	spinlock_t lock;
+	int outstanding_urbs;
+	int throttled;
+	struct urb *read_urbp[NUM_READ_URBS];
+};
+
+static void airprime_read_bulk_callback(struct urb *urb, struct pt_regs *regs)
+{
+	struct usb_serial_port *port = urb->context;
+	unsigned char *data = urb->transfer_buffer;
+	struct tty_struct *tty;
+	int result;
+
+	dbg("%s - port %d", __FUNCTION__, port->number);
+
+	if (urb->status) {
+		dbg("%s - nonzero read bulk status received: %d",
+		    __FUNCTION__, urb->status);
+		/* something happened, so free up the memory for this urb /*
+		if (urb->transfer_buffer) {
+			kfree (urb->transfer_buffer);
+			urb->transfer_buffer = NULL;
+		}
+		return;
+	}
+	usb_serial_debug_data(debug, &port->dev, __FUNCTION__, urb->actual_length, data);
+
+	tty = port->tty;
+	if (tty && urb->actual_length) {
+		tty_buffer_request_room(tty, urb->actual_length);
+		tty_insert_flip_string(tty, data, urb->actual_length);
+		tty_flip_buffer_push(tty);
+	}
+	/* should this use GFP_KERNEL? */
+	result = usb_submit_urb(urb, GFP_ATOMIC);
+	if (result)
+		dev_err(&port->dev, "%s - failed resubmitting read urb, error %d\n",
+			__FUNCTION__, result);
+	return;
+}
+
+static void airprime_write_bulk_callback(struct urb *urb, struct pt_regs *regs)
+{
+	struct usb_serial_port *port = urb->context;
+	struct airprime_private *priv = usb_get_serial_port_data(port);
+	unsigned long flags;
+
+	/* free up the transfer buffer, as usb_free_urb() does not do this */
+	kfree (urb->transfer_buffer);
+	dbg("%s - port %d", __FUNCTION__, port->number);
+
+	if (urb->status)
+		dbg("%s - nonzero write bulk status received: %d",
+		    __FUNCTION__, urb->status);
+	spin_lock_irqsave(&priv->lock, flags);
+	--priv->outstanding_urbs;
+	spin_unlock_irqrestore(&priv->lock, flags);
+
+	usb_serial_port_softint(port);
+}
+
+static int airprime_open(struct usb_serial_port *port, struct file *filp)
+{
+	struct airprime_private *priv = usb_get_serial_port_data(port);
+	struct usb_serial *serial = port->serial;
+	struct urb *urb;
+	char *buffer;
+	int i;
+	int result = 0;
+
+	dbg("%s - port %d", __FUNCTION__, port->number);
+
+	/* initialize our private data structure if it isn't already created */
+	if (!priv) {
+		priv = kzalloc(sizeof(*priv), GFP_KERNEL);
+		if (!priv)
+			return -ENOMEM;
+		spin_lock_init(&priv->lock);
+		usb_set_serial_port_data(port, priv);
+	}
+	/* TODO handle error conditions better, right now we leak memory */
+	for (i = 0; i < NUM_READ_URBS; ++i) {
+		buffer = kmalloc(buffer_size, GFP_KERNEL);
+		if (!buffer) {
+			dev_err(&port->dev, "%s - out of memory.\n",
+				__FUNCTION__);
+			return -ENOMEM;
+		}
+		urb = usb_alloc_urb(0, GFP_KERNEL);
+		if (!urb) {
+			dev_err(&port->dev, "%s - no more urbs?\n",
+				__FUNCTION__);
+			return -ENOMEM;
+		}
+		usb_fill_bulk_urb(urb, serial->dev,
+				  usb_rcvbulkpipe(serial->dev,
+						  port->bulk_out_endpointAddress),
+				  buffer, buffer_size,
+				  airprime_read_bulk_callback, port);
+		result = usb_submit_urb(urb, GFP_KERNEL);
+		if (result) {
+			dev_err(&port->dev,
+				"%s - failed submitting read urb %d for port %d, error %d\n",
+				__FUNCTION__, i, port->number, result);
+			return result;
+		}
+		/* fun with reference counting, when this urb is finished, the
+		 * host driver will free it up automatically */
+		/* don't do this here, we need the urb to stay around until the close
+		   function can take care of it */
+		//usb_free_urb (urb);
+		/* instead remember this urb so we can kill it when the
+		   port is closed */
+		priv->read_urbp[i] = urb;
+	}
+	return result;
+}
+
+static void airprime_close(struct usb_serial_port *port, struct file * filp)
+{
+	struct airprime_private *priv = usb_get_serial_port_data(port);
+	int i;
+
+	dbg("%s - port %d", __FUNCTION__, port->number);
+
+	/* killing the urb will invoke read_bulk_callback() with an error status,
+	   so the transfer buffer will be freed there */
+	for (i = 0; i < NUM_READ_URBS; ++i) {
+		usb_kill_urb (priv->read_urbp[i]);
+		usb_free_urb (priv->read_urbp[i]);
+	}
+
+	/* free up private structure? */
+}
+
+static int airprime_write(struct usb_serial_port *port,
+			  const unsigned char *buf, int count)
+{
+	struct airprime_private *priv = usb_get_serial_port_data(port);
+	struct usb_serial *serial = port->serial;
+	struct urb *urb;
+	unsigned char *buffer;
+	unsigned long flags;
+	int status;
+	dbg("%s - port %d", __FUNCTION__, port->number);
+
+	spin_lock_irqsave(&priv->lock, flags);
+	if (priv->outstanding_urbs > NUM_WRITE_URBS) {
+		spin_unlock_irqrestore(&priv->lock, flags);
+		dbg("%s - write limit hit\n", __FUNCTION__);
+		return 0;
+	}
+	spin_unlock_irqrestore(&priv->lock, flags);
+	buffer = kmalloc(count, GFP_ATOMIC);
+	if (!buffer) {
+		dev_err(&port->dev, "out of memory\n");
+		return -ENOMEM;
+	}
+	urb = usb_alloc_urb(0, GFP_ATOMIC);
+	if (!urb) {
+		dev_err(&port->dev, "no more free urbs\n");
+		kfree (buffer);
+		return -ENOMEM;
+	}
+	memcpy (buffer, buf, count);
+
+	usb_serial_debug_data(debug, &port->dev, __FUNCTION__, count, buffer);
+
+	usb_fill_bulk_urb(urb, serial->dev,
+			  usb_sndbulkpipe(serial->dev,
+					  port->bulk_out_endpointAddress),
+			  buffer, count,
+			  airprime_write_bulk_callback, port);
+
+	/* send it down the pipe */
+	status = usb_submit_urb(urb, GFP_ATOMIC);
+	if (status) {
+		dev_err(&port->dev,
+			"%s - usb_submit_urb(write bulk) failed with status = %d\n",
+			__FUNCTION__, status);
+		count = status;
+		kfree (buffer);
+	} else {
+		spin_lock_irqsave(&priv->lock, flags);
+		++priv->outstanding_urbs;
+		spin_unlock_irqrestore(&priv->lock, flags);
+	}
+	/* we are done with this urb, so let the host driver
+	 * really free it when it is finished with it */
+	usb_free_urb (urb);
+	return count;
+}
 
 static struct usb_driver airprime_driver = {
 	.name =		"airprime",
 	.probe =	usb_serial_probe,
 	.disconnect =	usb_serial_disconnect,
 	.id_table =	id_table,
-	.no_dynamic_id = 	1,
+	.no_dynamic_id =	1,
 };
 
 static struct usb_serial_driver airprime_device = {
@@ -42,13 +248,17 @@ static struct usb_serial_driver airprime
 	.num_interrupt_in =	NUM_DONT_CARE,
 	.num_bulk_in =		NUM_DONT_CARE,
 	.num_bulk_out =		NUM_DONT_CARE,
-	.num_ports =		1,
+	.open =			airprime_open,
+	.close =		airprime_close,
+	.write =		airprime_write,
 };
 
 static int __init airprime_init(void)
 {
 	int retval;
 
+	airprime_device.num_ports =
+		(endpoints > 0 && endpoints <= MAX_BULK_EPS) ? endpoints : NUM_BULK_EPS;
 	retval = usb_serial_register(&airprime_device);
 	if (retval)
 		return retval;
@@ -67,3 +277,10 @@ static void __exit airprime_exit(void)
 module_init(airprime_init);
 module_exit(airprime_exit);
 MODULE_LICENSE("GPL");
+
+module_param(debug, bool, S_IRUGO | S_IWUSR);
+MODULE_PARM_DESC(debug, "Debug enabled or not");
+module_param(buffer_size, int, 0);
+MODULE_PARM_DESC(buffer_size, "Size of the transfer buffers");
+module_param(endpoints, int, 0);
+MODULE_PARM_DESC(endpoints, "Number of bulk EPs to configure (default 3)");




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

* Re: [PATCH] Airprime driver improvements to allow full speed EvDO transfers
  2006-06-30  5:48 [PATCH] Airprime driver improvements to allow full speed EvDO transfers Andy Gay
@ 2006-06-30  7:10 ` Andrew Morton
  2006-06-30  8:52   ` Pete Zaitcev
                     ` (3 more replies)
  2006-06-30 20:04 ` Roland Dreier
                   ` (3 subsequent siblings)
  4 siblings, 4 replies; 40+ messages in thread
From: Andrew Morton @ 2006-06-30  7:10 UTC (permalink / raw)
  To: Andy Gay; +Cc: gregkh, linux-kernel, linux-usb-devel

On Fri, 30 Jun 2006 01:48:02 -0400
Andy Gay <andy@andynet.net> wrote:

> 
> Adapted from an earlier patch by Greg KH <gregkh@suse.de>.
> That patch added multiple read urbs and larger transfer buffers to allow
> data transfers at full EvDO speed.
> 
> This version includes additional device IDs and fixes a memory leak in
> the transfer buffer allocation.
> 
> Some (maybe all?) of the supported devices present multiple bulk endpoints,
> the additional EPs can be used for control and status functions.
> This version allocates 3 EPs by default, that can be changed using
> the 'endpoints' module parameter.
> 
> Tested with Sierra Wireless EM5625 and MC5720 embedded modules.
> 
> Device ID (0x0c88, 0x17da) for the Kyocera Wireless KPC650/Passport
> was added but is not yet tested.
> 
> ...
>
> +static void airprime_read_bulk_callback(struct urb *urb, struct pt_regs *regs)
> +{
> +	struct usb_serial_port *port = urb->context;
> +	unsigned char *data = urb->transfer_buffer;
> +	struct tty_struct *tty;
> +	int result;
> +
> +	dbg("%s - port %d", __FUNCTION__, port->number);
> +
> +	if (urb->status) {
> +		dbg("%s - nonzero read bulk status received: %d",
> +		    __FUNCTION__, urb->status);
> +		/* something happened, so free up the memory for this urb /*
> +		if (urb->transfer_buffer) {
> +			kfree (urb->transfer_buffer);
> +			urb->transfer_buffer = NULL;
> +		}
> +		return;
> +	}
> +	usb_serial_debug_data(debug, &port->dev, __FUNCTION__, urb->actual_length, data);
> +
> +	tty = port->tty;
> +	if (tty && urb->actual_length) {
> +		tty_buffer_request_room(tty, urb->actual_length);
> +		tty_insert_flip_string(tty, data, urb->actual_length);

Is it correct to ignore the return value from those two functions?

> +		tty_flip_buffer_push(tty);
> +	}
> +	/* should this use GFP_KERNEL? */
> +	result = usb_submit_urb(urb, GFP_ATOMIC);

If possible, yep.

> ...
>
> +static int airprime_open(struct usb_serial_port *port, struct file *filp)
> +{
> +	struct airprime_private *priv = usb_get_serial_port_data(port);
> +	struct usb_serial *serial = port->serial;
> +	struct urb *urb;
> +	char *buffer;
> +	int i;
> +	int result = 0;
> +
> +	dbg("%s - port %d", __FUNCTION__, port->number);
> +
> +	/* initialize our private data structure if it isn't already created */
> +	if (!priv) {
> +		priv = kzalloc(sizeof(*priv), GFP_KERNEL);
> +		if (!priv)
> +			return -ENOMEM;
> +		spin_lock_init(&priv->lock);
> +		usb_set_serial_port_data(port, priv);
> +	}
> +	/* TODO handle error conditions better, right now we leak memory */
> +	for (i = 0; i < NUM_READ_URBS; ++i) {
> +		buffer = kmalloc(buffer_size, GFP_KERNEL);
> +		if (!buffer) {
> +			dev_err(&port->dev, "%s - out of memory.\n",
> +				__FUNCTION__);
> +			return -ENOMEM;
> +		}
> +		urb = usb_alloc_urb(0, GFP_KERNEL);
> +		if (!urb) {
> +			dev_err(&port->dev, "%s - no more urbs?\n",
> +				__FUNCTION__);
> +			return -ENOMEM;
> +		}
> +		usb_fill_bulk_urb(urb, serial->dev,
> +				  usb_rcvbulkpipe(serial->dev,
> +						  port->bulk_out_endpointAddress),
> +				  buffer, buffer_size,
> +				  airprime_read_bulk_callback, port);
> +		result = usb_submit_urb(urb, GFP_KERNEL);
> +		if (result) {
> +			dev_err(&port->dev,
> +				"%s - failed submitting read urb %d for port %d, error %d\n",
> +				__FUNCTION__, i, port->number, result);
> +			return result;
> +		}
> +		/* fun with reference counting, when this urb is finished, the
> +		 * host driver will free it up automatically */
> +		/* don't do this here, we need the urb to stay around until the close
> +		   function can take care of it */
> +		//usb_free_urb (urb);
> +		/* instead remember this urb so we can kill it when the
> +		   port is closed */
> +		priv->read_urbp[i] = urb;
> +	}
> +	return result;
> +}
> +

This function leaks memory all over the place if something goes wrong.

Please redesign it to have a single `return' statement.  You'll find that'll
help avoid leaks now and during any later enhancements.


> +{
> +	struct airprime_private *priv = usb_get_serial_port_data(port);
> +	int i;
> +
> +	dbg("%s - port %d", __FUNCTION__, port->number);
> +
> +	/* killing the urb will invoke read_bulk_callback() with an error status,
> +	   so the transfer buffer will be freed there */
> +	for (i = 0; i < NUM_READ_URBS; ++i) {
> +		usb_kill_urb (priv->read_urbp[i]);
> +		usb_free_urb (priv->read_urbp[i]);
> +	}
> +
> +	/* free up private structure? */

Yes please ;)

> +}
> +
> +static int airprime_write(struct usb_serial_port *port,
> +			  const unsigned char *buf, int count)
> +{
> +	struct airprime_private *priv = usb_get_serial_port_data(port);
> +	struct usb_serial *serial = port->serial;
> +	struct urb *urb;
> +	unsigned char *buffer;
> +	unsigned long flags;
> +	int status;
> +	dbg("%s - port %d", __FUNCTION__, port->number);
> +
> +	spin_lock_irqsave(&priv->lock, flags);
> +	if (priv->outstanding_urbs > NUM_WRITE_URBS) {
> +		spin_unlock_irqrestore(&priv->lock, flags);
> +		dbg("%s - write limit hit\n", __FUNCTION__);
> +		return 0;
> +	}
> +	spin_unlock_irqrestore(&priv->lock, flags);
> +	buffer = kmalloc(count, GFP_ATOMIC);
> +	if (!buffer) {
> +		dev_err(&port->dev, "out of memory\n");
> +		return -ENOMEM;
> +	}
> +	urb = usb_alloc_urb(0, GFP_ATOMIC);
> +	if (!urb) {
> +		dev_err(&port->dev, "no more free urbs\n");
> +		kfree (buffer);
> +		return -ENOMEM;
> +	}
> +	memcpy (buffer, buf, count);
> +
> +	usb_serial_debug_data(debug, &port->dev, __FUNCTION__, count, buffer);
> +
> +	usb_fill_bulk_urb(urb, serial->dev,
> +			  usb_sndbulkpipe(serial->dev,
> +					  port->bulk_out_endpointAddress),
> +			  buffer, count,
> +			  airprime_write_bulk_callback, port);
> +
> +	/* send it down the pipe */
> +	status = usb_submit_urb(urb, GFP_ATOMIC);
> +	if (status) {
> +		dev_err(&port->dev,
> +			"%s - usb_submit_urb(write bulk) failed with status = %d\n",
> +			__FUNCTION__, status);
> +		count = status;
> +		kfree (buffer);
> +	} else {
> +		spin_lock_irqsave(&priv->lock, flags);
> +		++priv->outstanding_urbs;
> +		spin_unlock_irqrestore(&priv->lock, flags);
> +	}
> +	/* we are done with this urb, so let the host driver
> +	 * really free it when it is finished with it */
> +	usb_free_urb (urb);
> +	return count;
> +}

Is usb_serial_driver.write() really called in a context in which it is
forced to use GFP_ATOMIC?

Again, implementing this function as single-exit would make it easier to
maintain.

> +MODULE_PARM_DESC(debug, "Debug enabled or not");

Just "Debug enabled".

> +module_param(buffer_size, int, 0);
> +MODULE_PARM_DESC(buffer_size, "Size of the transfer buffers");

Units?


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

* Re: [PATCH] Airprime driver improvements to allow full speed EvDO transfers
  2006-06-30  7:10 ` Andrew Morton
@ 2006-06-30  8:52   ` Pete Zaitcev
  2006-06-30 16:59     ` Andy Gay
  2006-06-30 10:51   ` Sergei Organov
                     ` (2 subsequent siblings)
  3 siblings, 1 reply; 40+ messages in thread
From: Pete Zaitcev @ 2006-06-30  8:52 UTC (permalink / raw)
  To: Andrew Morton; +Cc: andy, gregkh, linux-kernel, linux-usb-devel, zaitcev

On Fri, 30 Jun 2006 00:10:21 -0700, Andrew Morton <akpm@osdl.org> wrote:

> > +static void airprime_read_bulk_callback(struct urb *urb, struct pt_regs *regs)
>.......
> > +	/* should this use GFP_KERNEL? */
> > +	result = usb_submit_urb(urb, GFP_ATOMIC);
> 
> If possible, yep.

You can't be serious. It's a callback function we're discussing here,
and you even quoted it.

> > +	/* free up private structure? */
> 
> Yes please ;)

+1

> Is usb_serial_driver.write() really called in a context in which it is
> forced to use GFP_ATOMIC?

There are cases when it is. It happens when a line discipline does it.
The n_tty does it if the line is in cooked mode, which is the default.
n_hdlc does it always, though I have no idea if this is applicable
to airprime. I think PPP writes from a tasklet as well.

The idea to allocate a URB for every little user write bothers me as
well. It was a dirty code thrown together quickly by someone who could
not be bothered to use a circular buffer and two URBs. It was fine
for the visor.c, but the Airprime is a higher performance card, and it
can be used in a home gateway with a low-power CPU. I'm not happy.

-- Pete

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

* Re: [PATCH] Airprime driver improvements to allow full speed EvDO transfers
  2006-06-30  7:10 ` Andrew Morton
  2006-06-30  8:52   ` Pete Zaitcev
@ 2006-06-30 10:51   ` Sergei Organov
  2006-06-30 12:13     ` [linux-usb-devel] " Alan Cox
  2006-06-30 16:35   ` Andy Gay
  2006-07-07 17:23   ` Sergei Organov
  3 siblings, 1 reply; 40+ messages in thread
From: Sergei Organov @ 2006-06-30 10:51 UTC (permalink / raw)
  To: Andrew Morton; +Cc: gregkh, linux-kernel, linux-usb-devel

Andrew Morton <akpm@osdl.org> writes:
> On Fri, 30 Jun 2006 01:48:02 -0400
> Andy Gay <andy@andynet.net> wrote:
[...]
>> +	if (tty && urb->actual_length) {
>> +		tty_buffer_request_room(tty, urb->actual_length);
>> +		tty_insert_flip_string(tty, data, urb->actual_length);
>
> Is it correct to ignore the return value from those two functions?

In fact, according to Alan Cox answer, the first call is useless here at
all, i.e., tty_buffer_request_room() is for subsequent
tty_insert_flip_char() calls in a loop, not for
tty_insert_flip_string(). tty_insert_flip_string() calls
tty_buffer_request_room() itself, and does it in a loop in attempt to
find as much memory as possible.

tty_insert_flip_string() returns number of bytes it has actually
inserted, but I don't believe one can do much if it returns less than
has been requested as it means that we are out of kernel memory.

Overall, it seems it should be just:

+	if (tty && urb->actual_length) {
+		tty_insert_flip_string(tty, data, urb->actual_length);

-- 
Sergei.

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

* Re: [linux-usb-devel] [PATCH] Airprime driver improvements to allow full speed EvDO transfers
  2006-06-30 12:13     ` [linux-usb-devel] " Alan Cox
@ 2006-06-30 12:02       ` Arjan van de Ven
  2006-06-30 13:34         ` Alan Cox
  0 siblings, 1 reply; 40+ messages in thread
From: Arjan van de Ven @ 2006-06-30 12:02 UTC (permalink / raw)
  To: Alan Cox
  Cc: Sergei Organov, Andrew Morton, gregkh, linux-kernel, linux-usb-devel


> > tty_insert_flip_string() returns number of bytes it has actually
> > inserted, but I don't believe one can do much if it returns less than
> > has been requested as it means that we are out of kernel memory.
> 
> Yes. I've been wondering if we should log the failure case somewhere,
> either as a tty-> object or printk.

printk gets... interesting if you use serial console ;)

both locking and buffer space wise


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

* Re: [linux-usb-devel] [PATCH] Airprime driver improvements to allow full speed EvDO transfers
  2006-06-30 10:51   ` Sergei Organov
@ 2006-06-30 12:13     ` Alan Cox
  2006-06-30 12:02       ` Arjan van de Ven
  0 siblings, 1 reply; 40+ messages in thread
From: Alan Cox @ 2006-06-30 12:13 UTC (permalink / raw)
  To: Sergei Organov; +Cc: Andrew Morton, gregkh, linux-kernel, linux-usb-devel

Ar Gwe, 2006-06-30 am 14:51 +0400, ysgrifennodd Sergei Organov:
> In fact, according to Alan Cox answer, the first call is useless here at
> all, i.e., tty_buffer_request_room() is for subsequent
> tty_insert_flip_char() calls in a loop, not for
> tty_insert_flip_string(). tty_insert_flip_string() calls
> tty_buffer_request_room() itself, and does it in a loop in attempt to
> find as much memory as possible.

Yep. Think of it as a hint that "I'm about to stuff xyz bytes into
memory" to get best memory efficiency.

> tty_insert_flip_string() returns number of bytes it has actually
> inserted, but I don't believe one can do much if it returns less than
> has been requested as it means that we are out of kernel memory.

Yes. I've been wondering if we should log the failure case somewhere,
either as a tty-> object or printk.

Alan


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

* Re: [linux-usb-devel] [PATCH] Airprime driver improvements to allow full speed EvDO transfers
  2006-06-30 12:02       ` Arjan van de Ven
@ 2006-06-30 13:34         ` Alan Cox
  0 siblings, 0 replies; 40+ messages in thread
From: Alan Cox @ 2006-06-30 13:34 UTC (permalink / raw)
  To: Arjan van de Ven
  Cc: Sergei Organov, Andrew Morton, gregkh, linux-kernel, linux-usb-devel

Ar Gwe, 2006-06-30 am 14:02 +0200, ysgrifennodd Arjan van de Ven:
> > Yes. I've been wondering if we should log the failure case somewhere,
> > either as a tty-> object or printk.
> 
> printk gets... interesting if you use serial console ;)
> both locking and buffer space wise

Not particularly. This is on the receive path not the transmit path so
the locking considerations don't arise.

Alan


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

* Re: [PATCH] Airprime driver improvements to allow full speed EvDO transfers
  2006-06-30  7:10 ` Andrew Morton
  2006-06-30  8:52   ` Pete Zaitcev
  2006-06-30 10:51   ` Sergei Organov
@ 2006-06-30 16:35   ` Andy Gay
  2006-07-07 17:23   ` Sergei Organov
  3 siblings, 0 replies; 40+ messages in thread
From: Andy Gay @ 2006-06-30 16:35 UTC (permalink / raw)
  To: Andrew Morton; +Cc: gregkh, linux-kernel, linux-usb-devel, Pete Zaitcev

On Fri, 2006-06-30 at 00:10 -0700, Andrew Morton wrote:

> > 
> > ...
> >
> > +static void airprime_read_bulk_callback(struct urb *urb, struct pt_regs *regs)
> > +{
...

> > +	tty = port->tty;
> > +	if (tty && urb->actual_length) {
> > +		tty_buffer_request_room(tty, urb->actual_length);
> > +		tty_insert_flip_string(tty, data, urb->actual_length);
> 
> Is it correct to ignore the return value from those two functions?
Not my code :) - generic.c and several other drivers do the same
thing... Not that that's an excuse, of course :)
Actually though, I think it's OK to ignore the tty_insert_flip_string
result. These adapters are used at layer 1 for ppp connection, the
higher layers will attempt to recover.

I will remove the tty_buffer_request_room() call though, as suggested by
Sergei Organov and Alan Cox.

> 
> > +		tty_flip_buffer_push(tty);
> > +	}
> > +	/* should this use GFP_KERNEL? */
> > +	result = usb_submit_urb(urb, GFP_ATOMIC);
> 
> If possible, yep.
Oops - that was a comment to myself I left in by mistake. As pointed out
by Pete Zaitcev, this is a callback function. I think it has to be
GFP_ATOMIC here, doesn't it?

> 
> > ...
> >
> > +static int airprime_open(struct usb_serial_port *port, struct file *filp)
> > +{
> > +	struct airprime_private *priv = usb_get_serial_port_data(port);
> > +	struct usb_serial *serial = port->serial;
> > +	struct urb *urb;
> > +	char *buffer;
> > +	int i;
> > +	int result = 0;
> > +
> > +	dbg("%s - port %d", __FUNCTION__, port->number);
> > +
> > +	/* initialize our private data structure if it isn't already created */
> > +	if (!priv) {
> > +		priv = kzalloc(sizeof(*priv), GFP_KERNEL);
> > +		if (!priv)
> > +			return -ENOMEM;
> > +		spin_lock_init(&priv->lock);
> > +		usb_set_serial_port_data(port, priv);
> > +	}
> > +	/* TODO handle error conditions better, right now we leak memory */
> > +	for (i = 0; i < NUM_READ_URBS; ++i) {
> > +		buffer = kmalloc(buffer_size, GFP_KERNEL);
> > +		if (!buffer) {
> > +			dev_err(&port->dev, "%s - out of memory.\n",
> > +				__FUNCTION__);
> > +			return -ENOMEM;
> > +		}
> > +		urb = usb_alloc_urb(0, GFP_KERNEL);
> > +		if (!urb) {
> > +			dev_err(&port->dev, "%s - no more urbs?\n",
> > +				__FUNCTION__);
> > +			return -ENOMEM;
> > +		}
> > +		usb_fill_bulk_urb(urb, serial->dev,
> > +				  usb_rcvbulkpipe(serial->dev,
> > +						  port->bulk_out_endpointAddress),
> > +				  buffer, buffer_size,
> > +				  airprime_read_bulk_callback, port);
> > +		result = usb_submit_urb(urb, GFP_KERNEL);
> > +		if (result) {
> > +			dev_err(&port->dev,
> > +				"%s - failed submitting read urb %d for port %d, error %d\n",
> > +				__FUNCTION__, i, port->number, result);
> > +			return result;
> > +		}
> > +		/* fun with reference counting, when this urb is finished, the
> > +		 * host driver will free it up automatically */
> > +		/* don't do this here, we need the urb to stay around until the close
> > +		   function can take care of it */
> > +		//usb_free_urb (urb);
> > +		/* instead remember this urb so we can kill it when the
> > +		   port is closed */
> > +		priv->read_urbp[i] = urb;
> > +	}
> > +	return result;
> > +}
> > +
> 
> This function leaks memory all over the place if something goes wrong.
Indeed. Hence the TODO comment.

> 
> Please redesign it to have a single `return' statement.  You'll find that'll
> help avoid leaks now and during any later enhancements.
OK, I'll work on that.
> 
> 
> > +{
> > +	struct airprime_private *priv = usb_get_serial_port_data(port);
> > +	int i;
> > +
> > +	dbg("%s - port %d", __FUNCTION__, port->number);
> > +
> > +	/* killing the urb will invoke read_bulk_callback() with an error status,
> > +	   so the transfer buffer will be freed there */
> > +	for (i = 0; i < NUM_READ_URBS; ++i) {
> > +		usb_kill_urb (priv->read_urbp[i]);
> > +		usb_free_urb (priv->read_urbp[i]);
> > +	}
> > +
> > +	/* free up private structure? */
> 
> Yes please ;)
Easily done. But we'd need another one next time the port is opened. Why
not just allocate it once and keep reusing it?

> 
> > +}
> > +
> > +static int airprime_write(struct usb_serial_port *port,
> > +			  const unsigned char *buf, int count)
> > +{
> > +	struct airprime_private *priv = usb_get_serial_port_data(port);
> > +	struct usb_serial *serial = port->serial;
> > +	struct urb *urb;
> > +	unsigned char *buffer;
> > +	unsigned long flags;
> > +	int status;
> > +	dbg("%s - port %d", __FUNCTION__, port->number);
> > +
> > +	spin_lock_irqsave(&priv->lock, flags);
> > +	if (priv->outstanding_urbs > NUM_WRITE_URBS) {
> > +		spin_unlock_irqrestore(&priv->lock, flags);
> > +		dbg("%s - write limit hit\n", __FUNCTION__);
> > +		return 0;
> > +	}
> > +	spin_unlock_irqrestore(&priv->lock, flags);
> > +	buffer = kmalloc(count, GFP_ATOMIC);
> > +	if (!buffer) {
> > +		dev_err(&port->dev, "out of memory\n");
> > +		return -ENOMEM;
> > +	}
> > +	urb = usb_alloc_urb(0, GFP_ATOMIC);
> > +	if (!urb) {
> > +		dev_err(&port->dev, "no more free urbs\n");
> > +		kfree (buffer);
> > +		return -ENOMEM;
> > +	}
> > +	memcpy (buffer, buf, count);
> > +
> > +	usb_serial_debug_data(debug, &port->dev, __FUNCTION__, count, buffer);
> > +
> > +	usb_fill_bulk_urb(urb, serial->dev,
> > +			  usb_sndbulkpipe(serial->dev,
> > +					  port->bulk_out_endpointAddress),
> > +			  buffer, count,
> > +			  airprime_write_bulk_callback, port);
> > +
> > +	/* send it down the pipe */
> > +	status = usb_submit_urb(urb, GFP_ATOMIC);
> > +	if (status) {
> > +		dev_err(&port->dev,
> > +			"%s - usb_submit_urb(write bulk) failed with status = %d\n",
> > +			__FUNCTION__, status);
> > +		count = status;
> > +		kfree (buffer);
> > +	} else {
> > +		spin_lock_irqsave(&priv->lock, flags);
> > +		++priv->outstanding_urbs;
> > +		spin_unlock_irqrestore(&priv->lock, flags);
> > +	}
> > +	/* we are done with this urb, so let the host driver
> > +	 * really free it when it is finished with it */
> > +	usb_free_urb (urb);
> > +	return count;
> > +}
> 
> Is usb_serial_driver.write() really called in a context in which it is
> forced to use GFP_ATOMIC?
No idea. Safer to leave this as is, I think.

> 
> Again, implementing this function as single-exit would make it easier to
> maintain.
OK.

> 
> > +MODULE_PARM_DESC(debug, "Debug enabled or not");
> 
> Just "Debug enabled".
> 
> > +module_param(buffer_size, int, 0);
> > +MODULE_PARM_DESC(buffer_size, "Size of the transfer buffers");
> 
> Units?
> 
I'll fix these.
Thanks for reviewing this.



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

* Re: [PATCH] Airprime driver improvements to allow full speed EvDO transfers
  2006-06-30  8:52   ` Pete Zaitcev
@ 2006-06-30 16:59     ` Andy Gay
  0 siblings, 0 replies; 40+ messages in thread
From: Andy Gay @ 2006-06-30 16:59 UTC (permalink / raw)
  To: Pete Zaitcev; +Cc: Andrew Morton, gregkh, linux-kernel, linux-usb-devel

On Fri, 2006-06-30 at 01:52 -0700, Pete Zaitcev wrote:

> The idea to allocate a URB for every little user write bothers me as
> well. It was a dirty code thrown together quickly by someone who could
> not be bothered to use a circular buffer and two URBs. It was fine
> for the visor.c, but the Airprime is a higher performance card, and it
> can be used in a home gateway with a low-power CPU. I'm not happy.

I agree completely. I was already planning to work on improving the
write path at some point.
The read path is more important though, these networks are asymmetric -
Sierra Wireless specifies max 2.4Mbps download vs 153Kbps upload for the
EM5625 and MC5720, presumably the other devices are similar. So this
patch was focused on getting the best read performance.

> 
> -- Pete


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

* Re: [PATCH] Airprime driver improvements to allow full speed EvDO transfers
  2006-06-30  5:48 [PATCH] Airprime driver improvements to allow full speed EvDO transfers Andy Gay
  2006-06-30  7:10 ` Andrew Morton
@ 2006-06-30 20:04 ` Roland Dreier
  2006-06-30 20:13   ` Andy Gay
  2006-07-02 18:48 ` Roland Dreier
                   ` (2 subsequent siblings)
  4 siblings, 1 reply; 40+ messages in thread
From: Roland Dreier @ 2006-06-30 20:04 UTC (permalink / raw)
  To: Andy Gay; +Cc: Greg KH, linux-kernel, linux-usb-devel

 > +		/* something happened, so free up the memory for this urb /*

an obvious glitch here at the end of the line...

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

* Re: [PATCH] Airprime driver improvements to allow full speed EvDO transfers
  2006-06-30 20:04 ` Roland Dreier
@ 2006-06-30 20:13   ` Andy Gay
  0 siblings, 0 replies; 40+ messages in thread
From: Andy Gay @ 2006-06-30 20:13 UTC (permalink / raw)
  To: Roland Dreier; +Cc: Greg KH, linux-kernel, linux-usb-devel

On Fri, 2006-06-30 at 13:04 -0700, Roland Dreier wrote:
>  > +		/* something happened, so free up the memory for this urb /*
> 
> an obvious glitch here at the end of the line...
Oops. Sorry 'bout that.. that comment had some more stuff that no longer
applies, I edited it just before I submitted the patch.

I'll make sure to at least compile test before submitting in future....



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

* Re: [PATCH] Airprime driver improvements to allow full speed EvDO transfers
  2006-06-30  5:48 [PATCH] Airprime driver improvements to allow full speed EvDO transfers Andy Gay
  2006-06-30  7:10 ` Andrew Morton
  2006-06-30 20:04 ` Roland Dreier
@ 2006-07-02 18:48 ` Roland Dreier
  2006-07-02 20:29   ` Andy Gay
  2006-07-03 15:43 ` [linux-usb-devel] " Ken Brush
  2006-07-11 18:31 ` Sergei Organov
  4 siblings, 1 reply; 40+ messages in thread
From: Roland Dreier @ 2006-07-02 18:48 UTC (permalink / raw)
  To: Andy Gay; +Cc: Greg KH, linux-kernel, linux-usb-devel

this works well on my kyocera kpc650 -- throughput is up to about 1
mbit/sec vs. ~250 kbit/sec with the stock airprime driver.

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

* Re: [PATCH] Airprime driver improvements to allow full speed EvDO transfers
  2006-07-02 18:48 ` Roland Dreier
@ 2006-07-02 20:29   ` Andy Gay
  2006-07-02 20:47     ` Roland Dreier
                       ` (2 more replies)
  0 siblings, 3 replies; 40+ messages in thread
From: Andy Gay @ 2006-07-02 20:29 UTC (permalink / raw)
  To: Roland Dreier
  Cc: Greg KH, linux-kernel, linux-usb-devel, Ken Brush, Jeremy Fitzhardinge

On Sun, 2006-07-02 at 11:48 -0700, Roland Dreier wrote:
> this works well on my kyocera kpc650 -- throughput is up to about 1
> mbit/sec vs. ~250 kbit/sec with the stock airprime driver.
> -
Thanks for the feedback.

I'm working on fixing the concerns Andrew Morton expressed regarding
memory leaks in the open function. I'll send an updated driver soon.

BTW - Jeremy suggested that the number of EPs to configure should be
determined from the device ID. Makes sense to me, but then many users
may have no use for the additional EPs. Alternatively, Greg suggested
that maybe this should split into 2 drivers. Any preferences, anyone?

I don't know which of these devices present multiple EPs though. Can you
send me the appropriate section from 'cat /proc/bus/usb/devices'?

Anyone with an actual Airprime (ID 0xf3d, 0x0112) or Novatel Merlin
(0x1410, 0x1110) please do the same.

Thanks -
Andy




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

* Re: [PATCH] Airprime driver improvements to allow full speed EvDO transfers
  2006-07-02 20:29   ` Andy Gay
@ 2006-07-02 20:47     ` Roland Dreier
  2006-07-03  7:00     ` Jeremy Fitzhardinge
  2006-07-03 17:00     ` Greg KH
  2 siblings, 0 replies; 40+ messages in thread
From: Roland Dreier @ 2006-07-02 20:47 UTC (permalink / raw)
  To: Andy Gay
  Cc: Greg KH, linux-kernel, linux-usb-devel, Ken Brush, Jeremy Fitzhardinge

 > I don't know which of these devices present multiple EPs though. Can you
 > send me the appropriate section from 'cat /proc/bus/usb/devices'?

Sure, no problem:

T:  Bus=05 Lev=01 Prnt=01 Port=00 Cnt=01 Dev#=  2 Spd=12  MxCh= 0
D:  Ver= 1.10 Cls=00(>ifc ) Sub=00 Prot=00 MxPS=64 #Cfgs=  1
P:  Vendor=0c88 ProdID=17da Rev= 0.00
S:  Manufacturer=Qualcomm, Incorporated
S:  Product=Qualcomm CDMA Technologies MSM
C:* #Ifs= 2 Cfg#= 1 Atr=a0 MxPwr=100mA
I:  If#= 0 Alt= 0 #EPs= 3 Cls=ff(vend.) Sub=ff Prot=ff Driver=airprime
E:  Ad=81(I) Atr=03(Int.) MxPS=  16 Ivl=128ms
E:  Ad=82(I) Atr=02(Bulk) MxPS=  64 Ivl=0ms
E:  Ad=02(O) Atr=02(Bulk) MxPS=  64 Ivl=0ms
I:  If#= 1 Alt= 0 #EPs= 2 Cls=ff(vend.) Sub=ff Prot=ff Driver=airprime
E:  Ad=84(I) Atr=02(Bulk) MxPS=  64 Ivl=0ms
E:  Ad=04(O) Atr=02(Bulk) MxPS=  64 Ivl=0ms

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

* Re: [PATCH] Airprime driver improvements to allow full speed EvDO transfers
  2006-07-02 20:29   ` Andy Gay
  2006-07-02 20:47     ` Roland Dreier
@ 2006-07-03  7:00     ` Jeremy Fitzhardinge
  2006-07-03 14:21       ` Andy Gay
  2006-07-03 17:00     ` Greg KH
  2 siblings, 1 reply; 40+ messages in thread
From: Jeremy Fitzhardinge @ 2006-07-03  7:00 UTC (permalink / raw)
  To: Andy Gay; +Cc: Roland Dreier, Greg KH, linux-kernel, linux-usb-devel, Ken Brush

Andy Gay wrote:
> BTW - Jeremy suggested that the number of EPs to configure should be
> determined from the device ID. Makes sense to me, but then many users
> may have no use for the additional EPs. Alternatively, Greg suggested
> that maybe this should split into 2 drivers. Any preferences, anyone?
>   
I think if the hardware has the EPs, they should be exposed by the 
driver.  You can tweak usermode as to whether they get device nodes, 
what they're called, etc.
> I don't know which of these devices present multiple EPs though. Can you
> send me the appropriate section from 'cat /proc/bus/usb/devices'?
>   
Phil Karn mentions on http://www.ka9q.net/5220.html:

    It may help to know what's actually inside the 5220 card. It
    contains a Qualcomm MSM 5500 mobile station modem chip that
    implements the actual 1xEV-DO functionality. This chip has a native
    USB 1.1 interface that emulates two USB serial ports. The first
    provides a classic serial modem interface that accepts AT commands
    and PPP data. The second is reserved for diagnostics and is unused.

For completeness:

T:  Bus=03 Lev=01 Prnt=01 Port=00 Cnt=01 Dev#=  2 Spd=12  MxCh= 0
D:  Ver= 1.10 Cls=00(>ifc ) Sub=00 Prot=00 MxPS=64 #Cfgs=  1
P:  Vendor=1199 ProdID=0218 Rev= 0.01
S:  Manufacturer=Sierra Wireless
S:  Product=Sierra Wireless MC5720 Modem
C:* #Ifs= 1 Cfg#= 1 Atr=e0 MxPwr=  0mA
I:  If#= 0 Alt= 0 #EPs= 7 Cls=ff(vend.) Sub=ff Prot=ff Driver=airprime
E:  Ad=81(I) Atr=03(Int.) MxPS=  16 Ivl=128ms
E:  Ad=82(I) Atr=02(Bulk) MxPS=  64 Ivl=0ms
E:  Ad=02(O) Atr=02(Bulk) MxPS=  64 Ivl=0ms
E:  Ad=84(I) Atr=02(Bulk) MxPS=  64 Ivl=0ms
E:  Ad=04(O) Atr=02(Bulk) MxPS=  64 Ivl=0ms
E:  Ad=85(I) Atr=02(Bulk) MxPS=  64 Ivl=0ms
E:  Ad=05(O) Atr=02(Bulk) MxPS=  64 Ivl=0ms


    J

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

* Re: [PATCH] Airprime driver improvements to allow full speed EvDO transfers
  2006-07-03  7:00     ` Jeremy Fitzhardinge
@ 2006-07-03 14:21       ` Andy Gay
  2006-07-03 16:28         ` Jeremy Fitzhardinge
  0 siblings, 1 reply; 40+ messages in thread
From: Andy Gay @ 2006-07-03 14:21 UTC (permalink / raw)
  To: Jeremy Fitzhardinge
  Cc: Roland Dreier, Greg KH, linux-kernel, linux-usb-devel, Ken Brush

On Mon, 2006-07-03 at 00:00 -0700, Jeremy Fitzhardinge wrote:
> Andy Gay wrote:
> > BTW - Jeremy suggested that the number of EPs to configure should be
> > determined from the device ID. Makes sense to me, but then many users
> > may have no use for the additional EPs. Alternatively, Greg suggested
> > that maybe this should split into 2 drivers. Any preferences, anyone?
> >   
> I think if the hardware has the EPs, they should be exposed by the 
> driver.  You can tweak usermode as to whether they get device nodes, 
> what they're called, etc.
I tend to agree. I'm thinking for now I should leave it as is, so it
defaults to configuring 3 EPs. Perhaps later I'll try to collect #EP
info for all the supported devices.

> > I don't know which of these devices present multiple EPs though. Can you
> > send me the appropriate section from 'cat /proc/bus/usb/devices'?
> >   
> Phil Karn mentions on http://www.ka9q.net/5220.html:
> 
>     It may help to know what's actually inside the 5220 card. It
>     contains a Qualcomm MSM 5500 mobile station modem chip that
>     implements the actual 1xEV-DO functionality. This chip has a native
>     USB 1.1 interface that emulates two USB serial ports. The first
>     provides a classic serial modem interface that accepts AT commands
>     and PPP data. The second is reserved for diagnostics and is unused.
> 
> For completeness:
> 
> T:  Bus=03 Lev=01 Prnt=01 Port=00 Cnt=01 Dev#=  2 Spd=12  MxCh= 0
> D:  Ver= 1.10 Cls=00(>ifc ) Sub=00 Prot=00 MxPS=64 #Cfgs=  1
> P:  Vendor=1199 ProdID=0218 Rev= 0.01
> S:  Manufacturer=Sierra Wireless
> S:  Product=Sierra Wireless MC5720 Modem
This is curious. I saw that '0218' in Greg's code, and 'corrected' it to
0018, because here's what I get with my MC5720:
P:  Vendor=1199 ProdID=0018 Rev= 0.01
S:  Manufacturer=Sierra Wireless
S:  Product=Sierra Wireless MC5720 Modem

So evidently there are also multiple variants of each modem.

> C:* #Ifs= 1 Cfg#= 1 Atr=e0 MxPwr=  0mA
> I:  If#= 0 Alt= 0 #EPs= 7 Cls=ff(vend.) Sub=ff Prot=ff Driver=airprime
> E:  Ad=81(I) Atr=03(Int.) MxPS=  16 Ivl=128ms
> E:  Ad=82(I) Atr=02(Bulk) MxPS=  64 Ivl=0ms
> E:  Ad=02(O) Atr=02(Bulk) MxPS=  64 Ivl=0ms
> E:  Ad=84(I) Atr=02(Bulk) MxPS=  64 Ivl=0ms
> E:  Ad=04(O) Atr=02(Bulk) MxPS=  64 Ivl=0ms
> E:  Ad=85(I) Atr=02(Bulk) MxPS=  64 Ivl=0ms
> E:  Ad=05(O) Atr=02(Bulk) MxPS=  64 Ivl=0ms
> 
> 
>     J


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

* Re: [linux-usb-devel] [PATCH] Airprime driver improvements to allow full speed EvDO transfers
  2006-06-30  5:48 [PATCH] Airprime driver improvements to allow full speed EvDO transfers Andy Gay
                   ` (2 preceding siblings ...)
  2006-07-02 18:48 ` Roland Dreier
@ 2006-07-03 15:43 ` Ken Brush
  2006-07-03 16:19   ` Andy Gay
  2006-07-11 18:31 ` Sergei Organov
  4 siblings, 1 reply; 40+ messages in thread
From: Ken Brush @ 2006-07-03 15:43 UTC (permalink / raw)
  To: Andy Gay; +Cc: Greg KH, linux-kernel, linux-usb-devel

On 6/29/06, Andy Gay <andy@andynet.net> wrote:
>
> Adapted from an earlier patch by Greg KH <gregkh@suse.de>.
> That patch added multiple read urbs and larger transfer buffers to allow
> data transfers at full EvDO speed.
>
> This version includes additional device IDs and fixes a memory leak in
> the transfer buffer allocation.
>
> Some (maybe all?) of the supported devices present multiple bulk endpoints,
> the additional EPs can be used for control and status functions.
> This version allocates 3 EPs by default, that can be changed using
> the 'endpoints' module parameter.
>
> Tested with Sierra Wireless EM5625 and MC5720 embedded modules.
>

With my aircard 580, I get 6 TTYUSB devices and a Urb too big message.
You should probably take the 580 out of the driver unless someone
actually has one and it works for them.

-Ken

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

* Re: [linux-usb-devel] [PATCH] Airprime driver improvements to allow full speed EvDO transfers
  2006-07-03 15:43 ` [linux-usb-devel] " Ken Brush
@ 2006-07-03 16:19   ` Andy Gay
  0 siblings, 0 replies; 40+ messages in thread
From: Andy Gay @ 2006-07-03 16:19 UTC (permalink / raw)
  To: Ken Brush; +Cc: Greg KH, linux-kernel, linux-usb-devel

On Mon, 2006-07-03 at 08:43 -0700, Ken Brush wrote:
> On 6/29/06, Andy Gay <andy@andynet.net> wrote:
> >
> > Adapted from an earlier patch by Greg KH <gregkh@suse.de>.
> > That patch added multiple read urbs and larger transfer buffers to allow
> > data transfers at full EvDO speed.
> >
> > This version includes additional device IDs and fixes a memory leak in
> > the transfer buffer allocation.
> >
> > Some (maybe all?) of the supported devices present multiple bulk endpoints,
> > the additional EPs can be used for control and status functions.
> > This version allocates 3 EPs by default, that can be changed using
> > the 'endpoints' module parameter.
> >
> > Tested with Sierra Wireless EM5625 and MC5720 embedded modules.
> >
> 
> With my aircard 580, I get 6 TTYUSB devices and a Urb too big message.
> You should probably take the 580 out of the driver unless someone
> actually has one and it works for them.
Well, that's the easy way out :)
But I'm willing to try to debug this, if you're game.

I don't know how it could see 6 EPs, unless you specify endpoints=6 when
you load the module. Maybe it sees it as 2 devices somehow?
Can you send me the relevant part of 'cat /proc/bus/usb/devices'?

Also the dmesg where you get the 'urb too big'. You could also try to
load the module with debug enabled.

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


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

* Re: [PATCH] Airprime driver improvements to allow full speed EvDO transfers
  2006-07-03 14:21       ` Andy Gay
@ 2006-07-03 16:28         ` Jeremy Fitzhardinge
  2006-07-03 17:00           ` Andy Gay
  0 siblings, 1 reply; 40+ messages in thread
From: Jeremy Fitzhardinge @ 2006-07-03 16:28 UTC (permalink / raw)
  To: Andy Gay; +Cc: Roland Dreier, Greg KH, linux-kernel, linux-usb-devel, Ken Brush

Andy Gay wrote:
>> I think if the hardware has the EPs, they should be exposed by the 
>> driver.  You can tweak usermode as to whether they get device nodes, 
>> what they're called, etc.
>>     
> I tend to agree. I'm thinking for now I should leave it as is, so it
> defaults to configuring 3 EPs. Perhaps later I'll try to collect #EP
> info for all the supported devices.
>   

Why not just expose all the EPs the hardware presents?  Is there a 
chance they might not be a serial connection?

> This is curious. I saw that '0218' in Greg's code, and 'corrected' it to
> 0018, because here's what I get with my MC5720:
>   

Yes, that patch was from me.

> P:  Vendor=1199 ProdID=0018 Rev= 0.01
> S:  Manufacturer=Sierra Wireless
> S:  Product=Sierra Wireless MC5720 Modem
>
> So evidently there are also multiple variants of each modem.
>   
My came embedded in a Thinkpad X60, and I think it is locked to 
Verizon.  The product ID might reflect either or both of those states.

    J

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

* Re: [PATCH] Airprime driver improvements to allow full speed EvDO transfers
  2006-07-02 20:29   ` Andy Gay
  2006-07-02 20:47     ` Roland Dreier
  2006-07-03  7:00     ` Jeremy Fitzhardinge
@ 2006-07-03 17:00     ` Greg KH
  2006-07-03 17:55       ` Andy Gay
  2 siblings, 1 reply; 40+ messages in thread
From: Greg KH @ 2006-07-03 17:00 UTC (permalink / raw)
  To: Andy Gay
  Cc: Roland Dreier, linux-kernel, linux-usb-devel, Ken Brush,
	Jeremy Fitzhardinge

On Sun, Jul 02, 2006 at 04:29:01PM -0400, Andy Gay wrote:
> On Sun, 2006-07-02 at 11:48 -0700, Roland Dreier wrote:
> > this works well on my kyocera kpc650 -- throughput is up to about 1
> > mbit/sec vs. ~250 kbit/sec with the stock airprime driver.
> > -
> Thanks for the feedback.
> 
> I'm working on fixing the concerns Andrew Morton expressed regarding
> memory leaks in the open function. I'll send an updated driver soon.
> 
> BTW - Jeremy suggested that the number of EPs to configure should be
> determined from the device ID. Makes sense to me, but then many users
> may have no use for the additional EPs. Alternatively, Greg suggested
> that maybe this should split into 2 drivers. Any preferences, anyone?

Yes, this driver is already split into 2 different ones (look in the
recent -mm releases).  Sierra wants to have their devices be in their
own driver, as the chip is a little different from the other ones.  This
means that those devices are now controlled by a driver called "sierra"
and the other devices still are working with the airprime driver.

This should hopefully fix the different endpoint issue, and allow new
devices to be supported properly, as Sierra Wireless is now maintaining
that driver.

Hope this helps,

greg k-h

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

* Re: [PATCH] Airprime driver improvements to allow full speed EvDO transfers
  2006-07-03 16:28         ` Jeremy Fitzhardinge
@ 2006-07-03 17:00           ` Andy Gay
  0 siblings, 0 replies; 40+ messages in thread
From: Andy Gay @ 2006-07-03 17:00 UTC (permalink / raw)
  To: Jeremy Fitzhardinge
  Cc: Roland Dreier, Greg KH, linux-kernel, linux-usb-devel, Ken Brush

On Mon, 2006-07-03 at 09:28 -0700, Jeremy Fitzhardinge wrote:
> Andy Gay wrote:
> >> I think if the hardware has the EPs, they should be exposed by the 
> >> driver.  You can tweak usermode as to whether they get device nodes, 
> >> what they're called, etc.
> >>     
> > I tend to agree. I'm thinking for now I should leave it as is, so it
> > defaults to configuring 3 EPs. Perhaps later I'll try to collect #EP
> > info for all the supported devices.
> >   
> 
> Why not just expose all the EPs the hardware presents?  Is there a 
> chance they might not be a serial connection?
Maybe. I believe it's possible to configure the Sierra kit to present an
NDIS interface. Not at all sure how that works. I'd have thought it
would be another layer on top of ppp, but who knows?

But I'm not sure I know how to do that anyway, without hardware to test
with.
For example, look at the info Roland sent me for his Kyocera:
I:  If#= 0 Alt= 0 #EPs= 3 Cls=ff(vend.) Sub=ff Prot=ff Driver=airprime
E:  Ad=81(I) Atr=03(Int.) MxPS=  16 Ivl=128ms
E:  Ad=82(I) Atr=02(Bulk) MxPS=  64 Ivl=0ms
E:  Ad=02(O) Atr=02(Bulk) MxPS=  64 Ivl=0ms
I:  If#= 1 Alt= 0 #EPs= 2 Cls=ff(vend.) Sub=ff Prot=ff Driver=airprime
E:  Ad=84(I) Atr=02(Bulk) MxPS=  64 Ivl=0ms
E:  Ad=04(O) Atr=02(Bulk) MxPS=  64 Ivl=0ms

Which is somewhat different from the MC5720 results you and I get.
Notice it appears to show 2 interfaces, with 1 pair of in/out bulk EPs
on each. We see 1 interface with 3 pairs. I don't know if/how that
difference needs to be addressed in the driver.

I wonder if that's why Ken got 6 EPs. Perhaps his 580 card presents 2
interfaces, with 3 EPs each.

Also, I know how to drive the 2nd EP on the MC5720. So I can test that
it actually works. But I have to rely on information I can't disclose to
do that (pesky NDAs). I don't know anything about the 3rd EP. And if
there really are 6 EPs on the 580, how the heck do we test that...

Seems the deeper I dig here, the murkier this all gets. I'm inclined to
keep it simple for now, at least... Really, how many users need those
extra EPs?

> 
> > This is curious. I saw that '0218' in Greg's code, and 'corrected' it to
> > 0018, because here's what I get with my MC5720:
> >   
> 
> Yes, that patch was from me.
> 
> > P:  Vendor=1199 ProdID=0018 Rev= 0.01
> > S:  Manufacturer=Sierra Wireless
> > S:  Product=Sierra Wireless MC5720 Modem
> >
> > So evidently there are also multiple variants of each modem.
> >   
> My came embedded in a Thinkpad X60, and I think it is locked to 
> Verizon.  The product ID might reflect either or both of those states.
> 
>     J


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

* Re: [PATCH] Airprime driver improvements to allow full speed EvDO transfers
  2006-07-03 17:00     ` Greg KH
@ 2006-07-03 17:55       ` Andy Gay
  2006-07-03 18:08         ` Jeremy Fitzhardinge
  2006-07-03 18:16         ` Greg KH
  0 siblings, 2 replies; 40+ messages in thread
From: Andy Gay @ 2006-07-03 17:55 UTC (permalink / raw)
  To: Greg KH
  Cc: Roland Dreier, linux-kernel, linux-usb-devel, Ken Brush,
	Jeremy Fitzhardinge

On Mon, 2006-07-03 at 10:00 -0700, Greg KH wrote:
> Yes, this driver is already split into 2 different ones (look in the
> recent -mm releases).  Sierra wants to have their devices be in their
> own driver, as the chip is a little different from the other ones.  This
> means that those devices are now controlled by a driver called "sierra"
> and the other devices still are working with the airprime driver.
> 
> This should hopefully fix the different endpoint issue, and allow new
> devices to be supported properly, as Sierra Wireless is now maintaining
> that driver.
Aha, good news. So this patch is already obsolete, for the Sierra stuff
anyway. And as I only have Sierra kit to work with, I reckon I should
drop out of this now.
I did make some changes to the last patch to do the cleanup stuff in the
open function, do you want to see those?

> Hope this helps,
> 
Sure does!

> greg k-h
> -
> To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html
> Please read the FAQ at  http://www.tux.org/lkml/


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

* Re: [PATCH] Airprime driver improvements to allow full speed EvDO transfers
  2006-07-03 17:55       ` Andy Gay
@ 2006-07-03 18:08         ` Jeremy Fitzhardinge
  2006-07-03 18:16         ` Greg KH
  1 sibling, 0 replies; 40+ messages in thread
From: Jeremy Fitzhardinge @ 2006-07-03 18:08 UTC (permalink / raw)
  To: Andy Gay; +Cc: Greg KH, Roland Dreier, linux-kernel, linux-usb-devel, Ken Brush

Andy Gay wrote:
> Aha, good news. So this patch is already obsolete, for the Sierra stuff
> anyway. And as I only have Sierra kit to work with, I reckon I should
> drop out of this now.
> I did make some changes to the last patch to do the cleanup stuff in the
> open function, do you want to see those?
>   
The Sierra driver as it stands is very bare-bones; it doesn't yet have 
the larger buffers.  So for now, I'll keep using the airprime one until 
sierra gets up to speed (though it seems like they should have a fair 
amount of common code).

    J

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

* Re: [PATCH] Airprime driver improvements to allow full speed EvDO transfers
  2006-07-03 17:55       ` Andy Gay
  2006-07-03 18:08         ` Jeremy Fitzhardinge
@ 2006-07-03 18:16         ` Greg KH
  2006-07-03 22:43           ` Andy Gay
  1 sibling, 1 reply; 40+ messages in thread
From: Greg KH @ 2006-07-03 18:16 UTC (permalink / raw)
  To: Andy Gay
  Cc: Roland Dreier, linux-kernel, linux-usb-devel, Ken Brush,
	Jeremy Fitzhardinge

On Mon, Jul 03, 2006 at 01:55:28PM -0400, Andy Gay wrote:
> On Mon, 2006-07-03 at 10:00 -0700, Greg KH wrote:
> > Yes, this driver is already split into 2 different ones (look in the
> > recent -mm releases).  Sierra wants to have their devices be in their
> > own driver, as the chip is a little different from the other ones.  This
> > means that those devices are now controlled by a driver called "sierra"
> > and the other devices still are working with the airprime driver.
> > 
> > This should hopefully fix the different endpoint issue, and allow new
> > devices to be supported properly, as Sierra Wireless is now maintaining
> > that driver.
> Aha, good news. So this patch is already obsolete, for the Sierra stuff
> anyway. And as I only have Sierra kit to work with, I reckon I should
> drop out of this now.

No, not at all.  I'll gladly add your patch to the sierra driver, if you
say it works for your devices.

> I did make some changes to the last patch to do the cleanup stuff in the
> open function, do you want to see those?

Yes, please send the latest version, and I'll apply it.

thanks,

greg k-h

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

* Re: [PATCH] Airprime driver improvements to allow full speed EvDO transfers
  2006-07-03 18:16         ` Greg KH
@ 2006-07-03 22:43           ` Andy Gay
  0 siblings, 0 replies; 40+ messages in thread
From: Andy Gay @ 2006-07-03 22:43 UTC (permalink / raw)
  To: Greg KH
  Cc: Roland Dreier, linux-kernel, linux-usb-devel, Ken Brush,
	Jeremy Fitzhardinge

On Mon, 2006-07-03 at 11:16 -0700, Greg KH wrote:
> On Mon, Jul 03, 2006 at 01:55:28PM -0400, Andy Gay wrote:
> > On Mon, 2006-07-03 at 10:00 -0700, Greg KH wrote:
> > > Yes, this driver is already split into 2 different ones (look in the
> > > recent -mm releases).  Sierra wants to have their devices be in their
> > > own driver, as the chip is a little different from the other ones.  This
> > > means that those devices are now controlled by a driver called "sierra"
> > > and the other devices still are working with the airprime driver.
> > > 
> > > This should hopefully fix the different endpoint issue, and allow new
> > > devices to be supported properly, as Sierra Wireless is now maintaining
> > > that driver.
> > Aha, good news. So this patch is already obsolete, for the Sierra stuff
> > anyway. And as I only have Sierra kit to work with, I reckon I should
> > drop out of this now.
> 
> No, not at all.  I'll gladly add your patch to the sierra driver, if you
> say it works for your devices.
> 
> > I did make some changes to the last patch to do the cleanup stuff in the
> > open function, do you want to see those?
> 
> Yes, please send the latest version, and I'll apply it.

OK, here it is!

-----

Adapted from an earlier patch by Greg KH <gregkh@suse.de>.
That patch added multiple read urbs and larger transfer buffers to allow
data transfers at full EvDO speed.

This version includes additional device IDs and fixes a memory leak in
the transfer buffer allocation.

Some (maybe all?) of the supported devices present multiple bulk endpoints,
the additional EPs can be used for control and status functions,
This version allocates 3 EPs by default, that can be changed using
the 'endpoints' module parameter.

Tested with Sierra Wireless EM5625 and MC5720 embedded modules.

Device ID (0x0c88, 0x17da) for the Kyocera Wireless KPC650/Passport
was added but is not yet tested.

---

Changes from previous patch:
 - fixed open function to clean up if anything goes wrong;
 - free private structure in close function;
 - add back alternate ID 0x0218 for the MC5720.

This is now reported as working for the Kyocera KPC650 (by Roland
Dreier <rdreier@cisco.com>), but as not working for the Sierra
Aircard 580 (by Ken Brush <kbrush@gmail.com>).

---

 drivers/usb/serial/airprime.c |  261 ++++++++++++++++++++++++++++++++++++++++-
 1 files changed, 255 insertions(+), 6 deletions(-)

diff --git a/drivers/usb/serial/airprime.c b/drivers/usb/serial/airprime.c
index 94b9ba0..1add380 100644
--- a/drivers/usb/serial/airprime.c
+++ b/drivers/usb/serial/airprime.c
@@ -1,36 +1,272 @@
 /*
  * AirPrime CDMA Wireless Serial USB driver
  *
- * Copyright (C) 2005 Greg Kroah-Hartman <gregkh@suse.de>
+ * Copyright (C) 2005-2006 Greg Kroah-Hartman <gregkh@suse.de>
  *
  *	This program is free software; you can redistribute it and/or
  *	modify it under the terms of the GNU General Public License version
  *	2 as published by the Free Software Foundation.
  */
-
 #include <linux/kernel.h>
 #include <linux/init.h>
 #include <linux/tty.h>
+#include <linux/tty_flip.h>
 #include <linux/module.h>
 #include <linux/usb.h>
 #include "usb-serial.h"
 
 static struct usb_device_id id_table [] = {
 	{ USB_DEVICE(0x0c88, 0x17da) }, /* Kyocera Wireless KPC650/Passport */
-	{ USB_DEVICE(0xf3d, 0x0112) },  /* AirPrime CDMA Wireless PC Card */
+	{ USB_DEVICE(0x0f3d, 0x0112) },	/* AirPrime CDMA Wireless PC Card */
 	{ USB_DEVICE(0x1410, 0x1110) }, /* Novatel Wireless Merlin CDMA */
+	{ USB_DEVICE(0x1199, 0x0017) }, /* Sierra Wireless EM5625 */
+	{ USB_DEVICE(0x1199, 0x0018) }, /* Sierra Wireless MC5720 */
+	{ USB_DEVICE(0x1199, 0x0218) }, /* Sierra Wireless MC5720 (alt) */
 	{ USB_DEVICE(0x1199, 0x0112) }, /* Sierra Wireless Aircard 580 */
-	{ USB_DEVICE(0x1199, 0x0218) }, /* Sierra Wireless MC5720 */
 	{ },
 };
 MODULE_DEVICE_TABLE(usb, id_table);
+#define URB_TRANSFER_BUFFER_SIZE	4096
+#define NUM_READ_URBS			4
+#define NUM_WRITE_URBS			4
+#define NUM_BULK_EPS			3
+#define MAX_BULK_EPS			6
+
+/* if overridden by the user, then use their value for the size of the
+ * read and write urbs, and the number of endpoints */
+static int buffer_size = URB_TRANSFER_BUFFER_SIZE;
+static int endpoints = NUM_BULK_EPS;
+static int debug;
+struct airprime_private {
+	spinlock_t lock;
+	int outstanding_urbs;
+	int throttled;
+	struct urb *read_urbp[NUM_READ_URBS];
+};
+
+static void airprime_read_bulk_callback(struct urb *urb, struct pt_regs *regs)
+{
+	struct usb_serial_port *port = urb->context;
+	unsigned char *data = urb->transfer_buffer;
+	struct tty_struct *tty;
+	int result;
+
+	dbg("%s - port %d", __FUNCTION__, port->number);
+
+	if (urb->status) {
+		dbg("%s - nonzero read bulk status received: %d",
+		    __FUNCTION__, urb->status);
+		/* something happened, so free up the memory for this urb */
+		if (urb->transfer_buffer) {
+			kfree (urb->transfer_buffer);
+			urb->transfer_buffer = NULL;
+		}
+		return;
+	}
+	usb_serial_debug_data(debug, &port->dev, __FUNCTION__, urb->actual_length, data);
+
+	tty = port->tty;
+	if (tty && urb->actual_length) {
+		tty_insert_flip_string (tty, data, urb->actual_length);
+		tty_flip_buffer_push (tty);
+	}
+
+	result = usb_submit_urb (urb, GFP_ATOMIC);
+	if (result)
+		dev_err(&port->dev, "%s - failed resubmitting read urb, error %d\n",
+			__FUNCTION__, result);
+	return;
+}
+
+static void airprime_write_bulk_callback(struct urb *urb, struct pt_regs *regs)
+{
+	struct usb_serial_port *port = urb->context;
+	struct airprime_private *priv = usb_get_serial_port_data(port);
+	unsigned long flags;
+
+	dbg("%s - port %d", __FUNCTION__, port->number);
+
+	/* free up the transfer buffer, as usb_free_urb() does not do this */
+	kfree (urb->transfer_buffer);
+
+	if (urb->status)
+		dbg("%s - nonzero write bulk status received: %d",
+		    __FUNCTION__, urb->status);
+	spin_lock_irqsave(&priv->lock, flags);
+	--priv->outstanding_urbs;
+	spin_unlock_irqrestore(&priv->lock, flags);
+
+	usb_serial_port_softint(port);
+}
+
+static int airprime_open(struct usb_serial_port *port, struct file *filp)
+{
+	struct airprime_private *priv = usb_get_serial_port_data(port);
+	struct usb_serial *serial = port->serial;
+	struct urb *urb;
+	char *buffer = NULL;
+	int i;
+	int result = 0;
+
+	dbg("%s - port %d", __FUNCTION__, port->number);
+
+	/* initialize our private data structure if it isn't already created */
+	if (!priv) {
+		priv = kzalloc(sizeof(*priv), GFP_KERNEL);
+		if (!priv) {
+			result = -ENOMEM;
+			goto out;
+		}
+		spin_lock_init(&priv->lock);
+		usb_set_serial_port_data(port, priv);
+	}
+
+	for (i = 0; i < NUM_READ_URBS; ++i) {
+		buffer = kmalloc(buffer_size, GFP_KERNEL);
+		if (!buffer) {
+			dev_err(&port->dev, "%s - out of memory.\n",
+				__FUNCTION__);
+			result = -ENOMEM;
+			goto errout;
+		}
+		urb = usb_alloc_urb(0, GFP_KERNEL);
+		if (!urb) {
+			dev_err(&port->dev, "%s - no more urbs?\n",
+				__FUNCTION__);
+			result = -ENOMEM;
+			goto errout;
+		}
+		usb_fill_bulk_urb(urb, serial->dev,
+				  usb_rcvbulkpipe(serial->dev,
+						  port->bulk_out_endpointAddress),
+				  buffer, buffer_size,
+				  airprime_read_bulk_callback, port);
+		result = usb_submit_urb(urb, GFP_KERNEL);
+		if (result) {
+			dev_err(&port->dev,
+				"%s - failed submitting read urb %d for port %d, error %d\n",
+				__FUNCTION__, i, port->number, result);
+			goto errout;
+		}
+		/* remember this urb so we can kill it when the port is closed */
+		priv->read_urbp[i] = urb;
+	}
+	goto out;
+
+ errout:
+	/* some error happened, cancel any submitted urbs and clean up anything that
+	   got allocated successfully */
+
+	for ( ; i >= 0; --i) {
+		urb = priv->read_urbp[i];
+		if (urb) {
+			/* This urb was submitted successfully. So we have to
+			   cancel it.
+			   Unlinking the urb will invoke read_bulk_callback()
+			   with an error status, so its transfer buffer will
+			   be freed there */
+			if (usb_unlink_urb (urb) != -EINPROGRESS) {
+				/* comments in drivers/usb/core/urb.c say this
+				   can only happen if the urb was never submitted,
+				   or has completed already.
+				   Either way we may have to free the transfer
+				   buffer here. */
+				if (urb->transfer_buffer) {
+					kfree (urb->transfer_buffer);
+					urb->transfer_buffer = NULL;
+				}
+			}
+			usb_free_urb (urb);
+		}
+	}
+
+ out:
+	return result;
+}
+
+static void airprime_close(struct usb_serial_port *port, struct file * filp)
+{
+	struct airprime_private *priv = usb_get_serial_port_data(port);
+	int i;
+
+	dbg("%s - port %d", __FUNCTION__, port->number);
+
+	/* killing the urb will invoke read_bulk_callback() with an error status,
+	   so the transfer buffer will be freed there */
+	for (i = 0; i < NUM_READ_URBS; ++i) {
+		usb_kill_urb (priv->read_urbp[i]);
+		usb_free_urb (priv->read_urbp[i]);
+	}
+
+	/* free up private structure */
+	kfree (priv);
+	usb_set_serial_port_data(port, NULL);
+}
+
+static int airprime_write(struct usb_serial_port *port,
+			  const unsigned char *buf, int count)
+{
+	struct airprime_private *priv = usb_get_serial_port_data(port);
+	struct usb_serial *serial = port->serial;
+	struct urb *urb;
+	unsigned char *buffer;
+	unsigned long flags;
+	int status;
+	dbg("%s - port %d", __FUNCTION__, port->number);
+
+	spin_lock_irqsave(&priv->lock, flags);
+	if (priv->outstanding_urbs > NUM_WRITE_URBS) {
+		spin_unlock_irqrestore(&priv->lock, flags);
+		dbg("%s - write limit hit\n", __FUNCTION__);
+		return 0;
+	}
+	spin_unlock_irqrestore(&priv->lock, flags);
+	buffer = kmalloc(count, GFP_ATOMIC);
+	if (!buffer) {
+		dev_err(&port->dev, "out of memory\n");
+		return -ENOMEM;
+	}
+	urb = usb_alloc_urb(0, GFP_ATOMIC);
+	if (!urb) {
+		dev_err(&port->dev, "no more free urbs\n");
+		kfree (buffer);
+		return -ENOMEM;
+	}
+	memcpy (buffer, buf, count);
+
+	usb_serial_debug_data(debug, &port->dev, __FUNCTION__, count, buffer);
+
+	usb_fill_bulk_urb(urb, serial->dev,
+			  usb_sndbulkpipe(serial->dev,
+					  port->bulk_out_endpointAddress),
+			  buffer, count,
+			  airprime_write_bulk_callback, port);
+
+	/* send it down the pipe */
+	status = usb_submit_urb(urb, GFP_ATOMIC);
+	if (status) {
+		dev_err(&port->dev,
+			"%s - usb_submit_urb(write bulk) failed with status = %d\n",
+			__FUNCTION__, status);
+		count = status;
+		kfree (buffer);
+	} else {
+		spin_lock_irqsave(&priv->lock, flags);
+		++priv->outstanding_urbs;
+		spin_unlock_irqrestore(&priv->lock, flags);
+	}
+	/* we are done with this urb, so let the host driver
+	 * really free it when it is finished with it */
+	usb_free_urb (urb);
+	return count;
+}
 
 static struct usb_driver airprime_driver = {
 	.name =		"airprime",
 	.probe =	usb_serial_probe,
 	.disconnect =	usb_serial_disconnect,
 	.id_table =	id_table,
-	.no_dynamic_id = 	1,
+	.no_dynamic_id =	1,
 };
 
 static struct usb_serial_driver airprime_device = {
@@ -42,13 +278,17 @@ static struct usb_serial_driver airprime
 	.num_interrupt_in =	NUM_DONT_CARE,
 	.num_bulk_in =		NUM_DONT_CARE,
 	.num_bulk_out =		NUM_DONT_CARE,
-	.num_ports =		1,
+	.open =			airprime_open,
+	.close =		airprime_close,
+	.write =		airprime_write,
 };
 
 static int __init airprime_init(void)
 {
 	int retval;
 
+	airprime_device.num_ports =
+		(endpoints > 0 && endpoints <= MAX_BULK_EPS) ? endpoints : NUM_BULK_EPS;
 	retval = usb_serial_register(&airprime_device);
 	if (retval)
 		return retval;
@@ -60,6 +300,8 @@ static int __init airprime_init(void)
 
 static void __exit airprime_exit(void)
 {
+	dbg("%s", __FUNCTION__);
+
 	usb_deregister(&airprime_driver);
 	usb_serial_deregister(&airprime_device);
 }
@@ -67,3 +309,10 @@ static void __exit airprime_exit(void)
 module_init(airprime_init);
 module_exit(airprime_exit);
 MODULE_LICENSE("GPL");
+
+module_param(debug, bool, S_IRUGO | S_IWUSR);
+MODULE_PARM_DESC(debug, "Debug enabled");
+module_param(buffer_size, int, 0);
+MODULE_PARM_DESC(buffer_size, "Size of the transfer buffers in bytes (default 4096)");
+module_param(endpoints, int, 0);
+MODULE_PARM_DESC(endpoints, "Number of bulk EPs to configure (default 3)");





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

* Re: [PATCH] Airprime driver improvements to allow full speed EvDO transfers
  2006-06-30  7:10 ` Andrew Morton
                     ` (2 preceding siblings ...)
  2006-06-30 16:35   ` Andy Gay
@ 2006-07-07 17:23   ` Sergei Organov
  2006-07-07 20:07     ` Alan Cox
  3 siblings, 1 reply; 40+ messages in thread
From: Sergei Organov @ 2006-07-07 17:23 UTC (permalink / raw)
  To: Andrew Morton; +Cc: gregkh, Alan Cox, linux-kernel, linux-usb-devel

Andrew Morton <akpm@osdl.org> writes:
> On Fri, 30 Jun 2006 01:48:02 -0400
> Andy Gay <andy@andynet.net> wrote:
[...]
>> +	if (tty && urb->actual_length) {
>> +		tty_buffer_request_room(tty, urb->actual_length);
>> +		tty_insert_flip_string(tty, data, urb->actual_length);
>
> Is it correct to ignore the return value from those two functions?
>
>> +		tty_flip_buffer_push(tty);

It seems that there is much worse problem here. The amount of data that
has been inserted by the tty_insert_flip_string() could be up to
URB_TRANSFER_BUFFER_SIZE (=4096 bytes) and may easily exceed
TTY_THRESHOLD_THROTTLE (=128 bytes) defined in the
char/n_tty.c. Pushing this data to the n_tty line discipline may then
overflow the line discipline buffer resulting in silent data loss. The
line discipline will call throttle() callback some time later then, but
it will be too late :(

This problem I've seen in my own driver with 2.4.x kernels, and I had
just re-checked it still exists with 2.6.17.4 kernel [had a hope Alan
changes to tty buffers fixed it, but no luck]. Besides, there are at
least 2 drivers in the kernel tree that try to deal with this problem,
char/hvsi.c, and serial/crisv10.c. For example, here is comment from
hvsi.c:

/*
 * We could get 252 bytes of data at once here. But the tty layer only
 * throttles us at TTY_THRESHOLD_THROTTLE (128) bytes, so we could overflow
 * it. Accordingly we won't send more than 128 bytes at a time to the flip
 * buffer, which will give the tty buffer a chance to throttle us. Should the
 * value of TTY_THRESHOLD_THROTTLE change in n_tty.c, this code should be
 * revisited.
 */

So, how is it supposed to work? Am I missing something?

Please also notice that attempts to overcome the problem in the drivers
look like fragile hacks that depend on intimate details of particular
line discipline. Any ideas how to fix it in general? Nice occasion to
apply "stable interfaces are evil" once again? ;)

-- 
Sergei.

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

* Re: [PATCH] Airprime driver improvements to allow full speed EvDO transfers
  2006-07-07 17:23   ` Sergei Organov
@ 2006-07-07 20:07     ` Alan Cox
  2006-07-10 10:36       ` Sergei Organov
  0 siblings, 1 reply; 40+ messages in thread
From: Alan Cox @ 2006-07-07 20:07 UTC (permalink / raw)
  To: Sergei Organov; +Cc: Andrew Morton, gregkh, linux-kernel, linux-usb-devel

Ar Gwe, 2006-07-07 am 21:23 +0400, ysgrifennodd Sergei Organov:
> It seems that there is much worse problem here. The amount of data that
> has been inserted by the tty_insert_flip_string() could be up to
> URB_TRANSFER_BUFFER_SIZE (=4096 bytes) and may easily exceed
> TTY_THRESHOLD_THROTTLE (=128 bytes) defined in the
> char/n_tty.c. 

You may throttle late but that is always true as there is an implicit
race between the hardware signals and the chip FIFO on all UART devices.
The buffering should be taking care of it, and the tty layer taking care
not to over stuff the ldisc which I thought Paul had fixed while doing
the locking wizardry

Alan




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

* Re: [PATCH] Airprime driver improvements to allow full speed EvDO transfers
  2006-07-07 20:07     ` Alan Cox
@ 2006-07-10 10:36       ` Sergei Organov
  2006-07-10 11:10         ` Alan Cox
  0 siblings, 1 reply; 40+ messages in thread
From: Sergei Organov @ 2006-07-10 10:36 UTC (permalink / raw)
  To: Alan Cox; +Cc: Andrew Morton, gregkh, linux-kernel, linux-usb-devel

Alan Cox <alan@lxorguk.ukuu.org.uk> writes:

> Ar Gwe, 2006-07-07 am 21:23 +0400, ysgrifennodd Sergei Organov:
>> It seems that there is much worse problem here. The amount of data that
>> has been inserted by the tty_insert_flip_string() could be up to
>> URB_TRANSFER_BUFFER_SIZE (=4096 bytes) and may easily exceed
>> TTY_THRESHOLD_THROTTLE (=128 bytes) defined in the
>> char/n_tty.c. 
>
> You may throttle late but that is always true as there is an implicit
> race between the hardware signals and the chip FIFO on all UART
> devices.

I don't talk about races here. What I see is simple logical software
problem arose due to poor interface between ldisc and tty. One can't
easily reproduce it with UART drivers unless UART FIFO is larger than
128 bytes, and even if such an UART exists, I think the RS232 is too
slow anyway so that in practice tty never tries to flip more than 128
bytes when ldisc buffer is almost full. I.e., it's hardware
characteristics of UARTs/RS232 that prevent the problem from being
triggered.

However, the problem is easily seen for USB-to-tty drivers where there
are no UARTS anywhere and speeds are rather high so that more than 4096
bytes (the line discipline buffer size) could be received before a task
has a chance to read from the line discipline buffer, and single flip
size is not limited by the hardware.

> The buffering should be taking care of it, and the tty layer taking care
> not to over stuff the ldisc 

Well, it should, but it doesn't seem to, -- that's the problem :(
Moreover, looking into the source code I don't see how tty can take care
not to over-stuff the ldisc. ldisc`s receive_buf() routine doesn't tell
the caller how many chars it actually consumed and silently throws away
whatever doesn't fit into its buffer. After it threw away unknown (to
the caller) amount of bytes, it calls throttle(), but first it's too
late and second tty flip code doesn't handle throttle() itself
anyway. So once again how this "tty layer taking care not to over stuff
the ldisc" is supposed to work?

Overall, the definition of the problem is: one can't reliably flip more
than 128 bytes at once without danger of missing of bytes. [This in turn
implies that with tty->low_latency set to 0 one can't reliably flip any
bytes at all(!) as N flips of M bytes each may be effectively converted
into delayed flip of M*N bytes.]

> which I thought Paul had fixed while doing the locking wizardry

I don't think locking has anything to do about it, but if it's indeed
fixed, where can I take the patch(es) as it doesn't seem to be fixed in
2.17.4?

-- 
Sergei.

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

* Re: [PATCH] Airprime driver improvements to allow full speed EvDO transfers
  2006-07-10 10:36       ` Sergei Organov
@ 2006-07-10 11:10         ` Alan Cox
  2006-07-10 15:54           ` Sergei Organov
  0 siblings, 1 reply; 40+ messages in thread
From: Alan Cox @ 2006-07-10 11:10 UTC (permalink / raw)
  To: Sergei Organov; +Cc: Andrew Morton, gregkh, linux-kernel, linux-usb-devel

Ar Llu, 2006-07-10 am 14:36 +0400, ysgrifennodd Sergei Organov:
> However, the problem is easily seen for USB-to-tty drivers where there
> are no UARTS anywhere and speeds are rather high so that more than 4096
> bytes (the line discipline buffer size) could be received before a task
> has a chance to read from the line discipline buffer, and single flip
> size is not limited by the hardware.

There are no flip buffers in 2.6.17, they've gone. The tty buffering is
now a proper queuing system.

> Moreover, looking into the source code I don't see how tty can take care
> not to over-stuff the ldisc. ldisc`s receive_buf() routine doesn't tell
> the caller how many chars it actually consumed and silently throws away

Not in the current kernel tree. The current tree does this:

       spin_lock_irqsave(&tty->buf.lock, flags);
        head = tty->buf.head;
        if (head != NULL) {
                tty->buf.head = NULL;
                for (;;) {
                        int count = head->commit - head->read;
                        if (!count) {
                                if (head->next == NULL)
                                        break;
                                tbuf = head;
                                head = head->next;
                                tty_buffer_free(tty, tbuf);
                                continue;
                        }
                        if (!tty->receive_room) {
                                schedule_delayed_work(&tty->buf.work, 1);
                                break;
                        }
                        if (count > tty->receive_room)
                                count = tty->receive_room;
                        char_buf = head->char_buf_ptr + head->read;
                        flag_buf = head->flag_buf_ptr + head->read;
                        head->read += count;
                        spin_unlock_irqrestore(&tty->buf.lock, flags);
                        disc->receive_buf(tty, char_buf, flag_buf, count);
                        spin_lock_irqsave(&tty->buf.lock, flags);
                }
                tty->buf.head = head;
        }
        spin_unlock_irqrestore(&tty->buf.lock, flags);


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

* Re: [PATCH] Airprime driver improvements to allow full speed EvDO transfers
  2006-07-10 11:10         ` Alan Cox
@ 2006-07-10 15:54           ` Sergei Organov
  2006-07-10 17:31             ` Alan Cox
  0 siblings, 1 reply; 40+ messages in thread
From: Sergei Organov @ 2006-07-10 15:54 UTC (permalink / raw)
  To: Alan Cox; +Cc: Andrew Morton, gregkh, linux-kernel, linux-usb-devel

Alan Cox <alan@lxorguk.ukuu.org.uk> writes:

> Ar Llu, 2006-07-10 am 14:36 +0400, ysgrifennodd Sergei Organov:
>> However, the problem is easily seen for USB-to-tty drivers where there
>> are no UARTS anywhere and speeds are rather high so that more than 4096
>> bytes (the line discipline buffer size) could be received before a task
>> has a chance to read from the line discipline buffer, and single flip
>> size is not limited by the hardware.
>
> There are no flip buffers in 2.6.17, they've gone.

Sure they gone, I've used "flip" because of tty_flip_buffer_push() has "flip"
in its name.

> The tty buffering is now a proper queuing system.

Yes, I know it is.

>
>> Moreover, looking into the source code I don't see how tty can take care
>> not to over-stuff the ldisc. ldisc`s receive_buf() routine doesn't tell
>> the caller how many chars it actually consumed and silently throws away
>
> Not in the current kernel tree. The current tree does this:

Which tree? I see rather different code in the 2.6.17.4, see below.

>
>        spin_lock_irqsave(&tty->buf.lock, flags);
>         head = tty->buf.head;
>         if (head != NULL) {
>                 tty->buf.head = NULL;
>                 for (;;) {
>                         int count = head->commit - head->read;
>                         if (!count) {
>                                 if (head->next == NULL)
>                                         break;
>                                 tbuf = head;
>                                 head = head->next;
>                                 tty_buffer_free(tty, tbuf);
>                                 continue;
>                         }
>                         if (!tty->receive_room) {
>                                 schedule_delayed_work(&tty->buf.work, 1);
>                                 break;
>                         }
>                         if (count > tty->receive_room)
>                                 count = tty->receive_room;
>                         char_buf = head->char_buf_ptr + head->read;
>                         flag_buf = head->flag_buf_ptr + head->read;
>                         head->read += count;
>                         spin_unlock_irqrestore(&tty->buf.lock, flags);
>                         disc->receive_buf(tty, char_buf, flag_buf, count);
>                         spin_lock_irqsave(&tty->buf.lock, flags);
>                 }
>                 tty->buf.head = head;
>         }
>         spin_unlock_irqrestore(&tty->buf.lock, flags);

Wow! The code you've quoted seems to be correct! But where did you get
it from? The version of flush_to_ldisc() from drivers/char/tty_io.c from
2.17.4 got last Friday from kernel.org does this:

	spin_lock_irqsave(&tty->buf.lock, flags);
	while((tbuf = tty->buf.head) != NULL) {
		while ((count = tbuf->commit - tbuf->read) != 0) {
			char_buf = tbuf->char_buf_ptr + tbuf->read;
			flag_buf = tbuf->flag_buf_ptr + tbuf->read;
			tbuf->read += count;
			spin_unlock_irqrestore(&tty->buf.lock, flags);
			disc->receive_buf(tty, char_buf, flag_buf, count);
			spin_lock_irqsave(&tty->buf.lock, flags);
		}
		if (tbuf->active)
			break;
		tty->buf.head = tbuf->next;
		if (tty->buf.head == NULL)
			tty->buf.tail = NULL;
		tty_buffer_free(tty, tbuf);
	}
	spin_unlock_irqrestore(&tty->buf.lock, flags);

Nowhere tty->receive_room is checked in tty_io.c! Am I missing something
or is this change not yet in the released kernels? If it's not yet
there, where can I get it and when is it expected to reach released
kernels?

-- 
Sergei.

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

* Re: [PATCH] Airprime driver improvements to allow full speed EvDO transfers
  2006-07-10 17:31             ` Alan Cox
@ 2006-07-10 17:24               ` Sergei Organov
  2006-07-13 14:17               ` Sergei Organov
  1 sibling, 0 replies; 40+ messages in thread
From: Sergei Organov @ 2006-07-10 17:24 UTC (permalink / raw)
  To: Alan Cox; +Cc: Andrew Morton, gregkh, linux-kernel, linux-usb-devel

Alan Cox <alan@lxorguk.ukuu.org.uk> writes:
> Ar Llu, 2006-07-10 am 19:54 +0400, ysgrifennodd Sergei Organov:
>> Wow! The code you've quoted seems to be correct! But where did you get
>> it from? The version of flush_to_ldisc() from drivers/char/tty_io.c from
>> 2.17.4 got last Friday from kernel.org does this:
>
>>From HEAD so it should make 2.6.18. Paul fixed this one.

Great news, -- the time I can finally throw away my ugly work-around is
coming!

Thank you a lot for clarifying the issue!

-- 
Sergei.

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

* Re: [PATCH] Airprime driver improvements to allow full speed EvDO transfers
  2006-07-10 15:54           ` Sergei Organov
@ 2006-07-10 17:31             ` Alan Cox
  2006-07-10 17:24               ` Sergei Organov
  2006-07-13 14:17               ` Sergei Organov
  0 siblings, 2 replies; 40+ messages in thread
From: Alan Cox @ 2006-07-10 17:31 UTC (permalink / raw)
  To: Sergei Organov; +Cc: Andrew Morton, gregkh, linux-kernel, linux-usb-devel

Ar Llu, 2006-07-10 am 19:54 +0400, ysgrifennodd Sergei Organov:
> Wow! The code you've quoted seems to be correct! But where did you get
> it from? The version of flush_to_ldisc() from drivers/char/tty_io.c from
> 2.17.4 got last Friday from kernel.org does this:

>From HEAD so it should make 2.6.18. Paul fixed this one.


Alan

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

* Re: [PATCH] Airprime driver improvements to allow full speed EvDO transfers
  2006-06-30  5:48 [PATCH] Airprime driver improvements to allow full speed EvDO transfers Andy Gay
                   ` (3 preceding siblings ...)
  2006-07-03 15:43 ` [linux-usb-devel] " Ken Brush
@ 2006-07-11 18:31 ` Sergei Organov
  2006-07-11 18:55   ` Andy Gay
  4 siblings, 1 reply; 40+ messages in thread
From: Sergei Organov @ 2006-07-11 18:31 UTC (permalink / raw)
  To: Andy Gay; +Cc: Greg KH, linux-kernel, linux-usb-devel

Andy Gay <andy@andynet.net> writes:
> Adapted from an earlier patch by Greg KH <gregkh@suse.de>.
> That patch added multiple read urbs and larger transfer buffers to allow
> data transfers at full EvDO speed.

Below are two more problems with the patch, one of which existed in the
original Greg's patch resulting in return with "Message too long"
(EMSGSIZE) from driver's open() function.

[...]

> +		/* something happened, so free up the memory for this urb /*

There should be '*/' at the end of this line, not '/*', otherwise the
driver even doesn't compile.

[...]
> +static int airprime_open(struct usb_serial_port *port, struct file *filp)
> +{
[...]
> +		usb_fill_bulk_urb(urb, serial->dev,
> +				  usb_rcvbulkpipe(serial->dev,
> +						  port->bulk_out_endpointAddress),

Here, it should obviously be port->bulk_in_endpointAddress, not
port->bulk_out_endpointAddress, otherwise devices that have endpoints
numeration like, say 0x01-out, 0x82-in (unlike more usual usual
0x01-out, 0x81-in), won't work returning -EMSGSIZE from open().

After these fixes, I've been able to run the driver with my own USB
device and achieved about 320 Kbytes/s read speed. That's still not very
exciting as I have another driver here in development that seems to be
able to do about 650 Kbytes/s with the same device.

-- 
Sergei.

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

* Re: [PATCH] Airprime driver improvements to allow full speed EvDO transfers
  2006-07-11 18:31 ` Sergei Organov
@ 2006-07-11 18:55   ` Andy Gay
  2006-07-12  9:20     ` Sergei Organov
  0 siblings, 1 reply; 40+ messages in thread
From: Andy Gay @ 2006-07-11 18:55 UTC (permalink / raw)
  To: Sergei Organov; +Cc: Greg KH, linux-kernel, linux-usb-devel

On Tue, 2006-07-11 at 22:31 +0400, Sergei Organov wrote:
> Andy Gay <andy@andynet.net> writes:
> > Adapted from an earlier patch by Greg KH <gregkh@suse.de>.
> > That patch added multiple read urbs and larger transfer buffers to allow
> > data transfers at full EvDO speed.
> 
> Below are two more problems with the patch, one of which existed in the
> original Greg's patch resulting in return with "Message too long"
> (EMSGSIZE) from driver's open() function.
> 
> [...]
> 
> > +		/* something happened, so free up the memory for this urb /*
> 
> There should be '*/' at the end of this line, not '/*', otherwise the
> driver even doesn't compile.

Sure. I posted an updated version including that fix -
http://lkml.org/lkml/2006/7/3/280

> 
> [...]
> > +static int airprime_open(struct usb_serial_port *port, struct file *filp)
> > +{
> [...]
> > +		usb_fill_bulk_urb(urb, serial->dev,
> > +				  usb_rcvbulkpipe(serial->dev,
> > +						  port->bulk_out_endpointAddress),
> 
> Here, it should obviously be port->bulk_in_endpointAddress, not
> port->bulk_out_endpointAddress, otherwise devices that have endpoints
> numeration like, say 0x01-out, 0x82-in (unlike more usual usual
> 0x01-out, 0x81-in), won't work returning -EMSGSIZE from open().

Sounds correct. Good catch!

> 
> After these fixes, I've been able to run the driver with my own USB
> device and achieved about 320 Kbytes/s read speed. That's still not very
> exciting as I have another driver here in development that seems to be
> able to do about 650 Kbytes/s with the same device.
> 
Nice. That's over 5Mbits/sec!

Is that on an EvDO network? I didn't know they could go that fast. The
EvDO network I'm testing on can only manage about 1Mbit/sec at best.




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

* Re: [PATCH] Airprime driver improvements to allow full speed EvDO transfers
  2006-07-11 18:55   ` Andy Gay
@ 2006-07-12  9:20     ` Sergei Organov
  0 siblings, 0 replies; 40+ messages in thread
From: Sergei Organov @ 2006-07-12  9:20 UTC (permalink / raw)
  To: Andy Gay; +Cc: Greg KH, linux-kernel, linux-usb-devel

Andy Gay <andy@andynet.net> writes:
> On Tue, 2006-07-11 at 22:31 +0400, Sergei Organov wrote:
>> Andy Gay <andy@andynet.net> writes:

[...]

>> > +		/* something happened, so free up the memory for this urb /*
>> 
>> There should be '*/' at the end of this line, not '/*', otherwise the
>> driver even doesn't compile.
>
> Sure. I posted an updated version including that fix -
> http://lkml.org/lkml/2006/7/3/280

OK, I've forgot about that one, sorry.

[...]

>> 
>> After these fixes, I've been able to run the driver with my own USB
>> device and achieved about 320 Kbytes/s read speed. That's still not very
>> exciting as I have another driver here in development that seems to be
>> able to do about 650 Kbytes/s with the same device.
>> 
> Nice. That's over 5Mbits/sec!
>
> Is that on an EvDO network? I didn't know they could go that fast. The
> EvDO network I'm testing on can only manage about 1Mbit/sec at best.

No, it is not, -- that's my own device I write firmware for. In our
earlier discussion about high-speed bulk-to-tty converter Greg suggested
to try to use improved airprime driver to see if it's fast enough, and
probably then we may come up with high speed generic bulk-to-tty
converter. If we finally get it done, the airprime and other similar
drivers may directly use it for read/write/handshake operations and
manage only their specifics themselves.

Now to the difference in speed. I think the main reason airprime can't
match 5Mbits/sec is copying of data into tty in the read callback. I use
specially crafted ring buffer of chars, memory from which is directly
passed to the single read URB, then I immediately resubmit the URB (with
the next chunk of memory from the ring buffer) in the read callback and
schedule tasklet to copy from the ring buffer to tty. This solution is
there from the old days when USB core didn't like submissions of
multiple URBs. Now I think a better approach could be to have a FIFO of
URBs along with their buffers where you put URBs in the read callback,
then get them in the tasklet, copy to tty, and re-submit. I didn't have
time to play with the latter approach though.

-- 
Sergei.

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

* Re: [PATCH] Airprime driver improvements to allow full speed EvDO transfers
  2006-07-10 17:31             ` Alan Cox
  2006-07-10 17:24               ` Sergei Organov
@ 2006-07-13 14:17               ` Sergei Organov
  2006-07-13 15:40                 ` Alan Cox
  1 sibling, 1 reply; 40+ messages in thread
From: Sergei Organov @ 2006-07-13 14:17 UTC (permalink / raw)
  To: Alan Cox; +Cc: Andrew Morton, gregkh, linux-kernel, linux-usb-devel

Alan Cox <alan@lxorguk.ukuu.org.uk> writes:
> Ar Llu, 2006-07-10 am 19:54 +0400, ysgrifennodd Sergei Organov:
>> Wow! The code you've quoted seems to be correct! But where did you get
>> it from? The version of flush_to_ldisc() from drivers/char/tty_io.c from
>> 2.17.4 got last Friday from kernel.org does this:
>
>> From HEAD so it should make 2.6.18. Paul fixed this one.

I've tested my driver with 2.6.18-rc1 and can confirm Paul changes
finally fixed this particular problem. However, this fix unveiled
different problem with the current tty buffering code.

The memory amount that could be used by tty buffers is
uncontrolled. I've arranged a test[1] that demonstrates that tty buffers
do indeed grow to the entire size of available memory at some conditions
resulting in kernel starting to kill random processes until the testing
process is killed.

This problem may occur with any tty driver that doesn't stop to insert
data into the tty buffers in throttled state. And yes, there are such
drivers in the tree. Before Paul's changes, the tty just dropped bytes
that aren't accepted by ldisc, so this problem had no chances to arise.

I think that either the amount of memory used by tty buffers should be
limited by a tty variable with a suitable default, or tty buffering
should be changed not to accept data from drivers in throttled state.
Alternatively, tty may rely on drivers not to insert data in the
throttled state, but then it's better to be written in big red letters
in the description of tty buffer interface routines. Though in the 2
latter cases drivers that insert too much data without pushing to ldisc
may cause similar problem. Anyway, you definitely know better what to do
about it.

[1] I have a USB device streaming data on its bulk endpoint. The device
is handled by improved airprime driver (usb-to-tty converter) that could
be found in Greg's patches. The driver attached the device to
/dev/ttyUSB0. The testing application just opened /dev/ttyUSB0 and went
to sleep, i.e., it just didn't read from the resulting fd. At these
conditions the slab memory reported in /proc/meminfo grew linearly in
time until in a few minutes kernel started to kill processes. The
testing process wasn't the first one the kernel killed. It killed X
server and some other applications until eventually it killed the
testing process at which point things returned to normal operation.

-- 
Sergei.

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

* Re: [PATCH] Airprime driver improvements to allow full speed EvDO transfers
  2006-07-13 14:17               ` Sergei Organov
@ 2006-07-13 15:40                 ` Alan Cox
  2006-07-13 18:20                   ` Sergei Organov
  0 siblings, 1 reply; 40+ messages in thread
From: Alan Cox @ 2006-07-13 15:40 UTC (permalink / raw)
  To: Sergei Organov; +Cc: Andrew Morton, gregkh, linux-kernel, linux-usb-devel

On Iau, 2006-07-13 at 18:17 +0400, Sergei Organov wrote:
> This problem may occur with any tty driver that doesn't stop to insert
> data into the tty buffers in throttled state. And yes, there are such
> drivers in the tree. Before Paul's changes, the tty just dropped bytes
> that aren't accepted by ldisc, so this problem had no chances to arise.

You must honour throttle. That has always been the case. At all times
you should attempt to homour tty->receive_room and also ->throttle. If
you don't it breaks. There will always be some "reaction time" overruns.

> latter cases drivers that insert too much data without pushing to ldisc
> may cause similar problem. Anyway, you definitely know better what to do
> about it.

Might be a good idea to put a limiter in before 2.6.18 proper just to
trap any other drivers that have that bug. At least printk a warning and
refuse the allocation once there is say 64K queued. That way the driver
author gets a hint all is not well.

Alan


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

* Re: [PATCH] Airprime driver improvements to allow full speed EvDO transfers
  2006-07-13 15:40                 ` Alan Cox
@ 2006-07-13 18:20                   ` Sergei Organov
  2006-07-13 19:08                     ` Greg KH
  0 siblings, 1 reply; 40+ messages in thread
From: Sergei Organov @ 2006-07-13 18:20 UTC (permalink / raw)
  To: Alan Cox; +Cc: Andrew Morton, gregkh, linux-kernel, linux-usb-devel

Alan Cox <alan@lxorguk.ukuu.org.uk> writes:
> On Iau, 2006-07-13 at 18:17 +0400, Sergei Organov wrote:
>> This problem may occur with any tty driver that doesn't stop to insert
>> data into the tty buffers in throttled state. And yes, there are such
>> drivers in the tree. Before Paul's changes, the tty just dropped bytes
>> that aren't accepted by ldisc, so this problem had no chances to arise.
>
> You must honour throttle. 

I do, it's Greg who doesn't ;) BTW, isn't it OK to just check for
tty->throttled where appropriate if I don't have anything special to do
at unthrottled/throttled transition time?

> That has always been the case. At all times you should attempt to
> homour tty->receive_room and also ->throttle. If you don't it breaks.

Yes, but the difference is what "it" actually is. Loosing some
characters at some rare or "might never in fact happen conditions" is
one "it", and exhausting kernel memory at (even more) rare conditions is
a different "it", isn't it?

Besides, if the throttle() is that important and failure to handle it is
a big mistake, why is it optional then? I mean why struct tty_operations
with throttle field set to NULL is accepted in the first place? The same
question is applicable to the struct usb_serial_driver.

>> latter cases drivers that insert too much data without pushing to ldisc
>> may cause similar problem. Anyway, you definitely know better what to do
>> about it.
>
> Might be a good idea to put a limiter in before 2.6.18 proper just to
> trap any other drivers that have that bug. At least printk a warning and
> refuse the allocation once there is say 64K queued. That way the driver
> author gets a hint all is not well.

I'm afraid that the limit won't work well as a hint for driver
developers that didn't honour throttle, as real applications do usually
read from the files they open, and therefore the problem most probably
won't be noticed for a long time.

Provided the limiter is put, why not to make it a variable with 64K
default?  Driver writers that for whatever reason decide they need more
in buffers will be able to change that, but then it will be their
deliberate decision, not just underestimation of consequences of failure
to handle throttle() due to a lack of knowledge.

Actually I think that the first thing to decide is if memory usage by
tty should be bounded or not, and if yes, should it be per-tty limit, or
total memory usage by all the ttys limit, or both. Those decisions I'd
probably base on how other kernel subsystems behave (TCP stack is the
first that comes to mind, and AFAIK buffering for every socket is
limited). Due to lack of broad knowledge of the kernel, I won't try to
insist on any solution, even though my experience in embedded systems
programming cries for bounded model.

And at the end, I'm going to RTFM ;)

The comment to the throttle routine in the kernel tree says:

 * 	This routine notifies the tty driver that input buffers for
 * 	the line discipline are close to full, and it should somehow
 * 	signal that no more characters should be sent to the tty.

"Linux Device Drivers" 3-d edition says:

 The throttle function is called when the tty core’s input buffers are
 getting full. The tty driver should try to signal to the device that
 no more characters should be sent to it.

None of these two suggests there could be such a global consequences of
attempting to insert data to the throttled tty as exhausted kernel
memory. The kernel version reads more strict to me, but LDD one is
apparently how people indeed understand it.

BTW, I'm curious if Greg wasn't aware throttle must be handled, or just
decided that it's not worth to, as neither generic nor airprime
usb-serial drivers handle throttle. Besides, the example tiny_tty.c
driver from the LDD doesn't handle throttle either. If even most
experienced and involved kernel developers do ignore the throttle(),
what should be expected from random Joe driver writer?

-- 
Sergei.

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

* Re: [PATCH] Airprime driver improvements to allow full speed EvDO transfers
  2006-07-13 18:20                   ` Sergei Organov
@ 2006-07-13 19:08                     ` Greg KH
  2006-07-14 10:13                       ` Sergei Organov
  0 siblings, 1 reply; 40+ messages in thread
From: Greg KH @ 2006-07-13 19:08 UTC (permalink / raw)
  To: Sergei Organov; +Cc: Alan Cox, Andrew Morton, linux-kernel, linux-usb-devel

On Thu, Jul 13, 2006 at 10:20:19PM +0400, Sergei Organov wrote:
> Alan Cox <alan@lxorguk.ukuu.org.uk> writes:
> > On Iau, 2006-07-13 at 18:17 +0400, Sergei Organov wrote:
> >> This problem may occur with any tty driver that doesn't stop to insert
> >> data into the tty buffers in throttled state. And yes, there are such
> >> drivers in the tree. Before Paul's changes, the tty just dropped bytes
> >> that aren't accepted by ldisc, so this problem had no chances to arise.
> >
> > You must honour throttle. 
> 
> I do, it's Greg who doesn't ;) BTW, isn't it OK to just check for
> tty->throttled where appropriate if I don't have anything special to do
> at unthrottled/throttled transition time?
> 
> > That has always been the case. At all times you should attempt to
> > homour tty->receive_room and also ->throttle. If you don't it breaks.
> 
> Yes, but the difference is what "it" actually is. Loosing some
> characters at some rare or "might never in fact happen conditions" is
> one "it", and exhausting kernel memory at (even more) rare conditions is
> a different "it", isn't it?
> 
> Besides, if the throttle() is that important and failure to handle it is
> a big mistake, why is it optional then? I mean why struct tty_operations
> with throttle field set to NULL is accepted in the first place? The same
> question is applicable to the struct usb_serial_driver.

Yes, I didn't realize it was required.  If it is, we should add this
change.

> >> latter cases drivers that insert too much data without pushing to ldisc
> >> may cause similar problem. Anyway, you definitely know better what to do
> >> about it.
> >
> > Might be a good idea to put a limiter in before 2.6.18 proper just to
> > trap any other drivers that have that bug. At least printk a warning and
> > refuse the allocation once there is say 64K queued. That way the driver
> > author gets a hint all is not well.
> 
> I'm afraid that the limit won't work well as a hint for driver
> developers that didn't honour throttle, as real applications do usually
> read from the files they open, and therefore the problem most probably
> won't be noticed for a long time.
> 
> Provided the limiter is put, why not to make it a variable with 64K
> default?  Driver writers that for whatever reason decide they need more
> in buffers will be able to change that, but then it will be their
> deliberate decision, not just underestimation of consequences of failure
> to handle throttle() due to a lack of knowledge.
> 
> Actually I think that the first thing to decide is if memory usage by
> tty should be bounded or not, and if yes, should it be per-tty limit, or
> total memory usage by all the ttys limit, or both. Those decisions I'd
> probably base on how other kernel subsystems behave (TCP stack is the
> first that comes to mind, and AFAIK buffering for every socket is
> limited). Due to lack of broad knowledge of the kernel, I won't try to
> insist on any solution, even though my experience in embedded systems
> programming cries for bounded model.
> 
> And at the end, I'm going to RTFM ;)
> 
> The comment to the throttle routine in the kernel tree says:
> 
>  * 	This routine notifies the tty driver that input buffers for
>  * 	the line discipline are close to full, and it should somehow
>  * 	signal that no more characters should be sent to the tty.
> 
> "Linux Device Drivers" 3-d edition says:
> 
>  The throttle function is called when the tty core???s input buffers are
>  getting full. The tty driver should try to signal to the device that
>  no more characters should be sent to it.
> 
> None of these two suggests there could be such a global consequences of
> attempting to insert data to the throttled tty as exhausted kernel
> memory. The kernel version reads more strict to me, but LDD one is
> apparently how people indeed understand it.

Well, as I wrote that chapter in LDD, that was how I understood it :)

> BTW, I'm curious if Greg wasn't aware throttle must be handled, or just
> decided that it's not worth to, as neither generic nor airprime
> usb-serial drivers handle throttle.

I wasn't aware that it was required.

> Besides, the example tiny_tty.c driver from the LDD doesn't handle
> throttle either.

I wrote that too :)

thanks,

greg k-h

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

* Re: [PATCH] Airprime driver improvements to allow full speed EvDO transfers
  2006-07-13 19:08                     ` Greg KH
@ 2006-07-14 10:13                       ` Sergei Organov
  0 siblings, 0 replies; 40+ messages in thread
From: Sergei Organov @ 2006-07-14 10:13 UTC (permalink / raw)
  To: Greg KH; +Cc: Alan Cox, Andrew Morton, linux-kernel, linux-usb-devel

Greg KH <gregkh@suse.de> writes:
> On Thu, Jul 13, 2006 at 10:20:19PM +0400, Sergei Organov wrote:
[...]
>> Besides, if the throttle() is that important and failure to handle it is
>> a big mistake, why is it optional then? I mean why struct tty_operations
>> with throttle field set to NULL is accepted in the first place? The same
>> question is applicable to the struct usb_serial_driver.
>
> Yes, I didn't realize it was required.

That was my point, -- people don't realize it is dangerous not to handle
throttle, and in fact it was not that dangerous before new tty buffering
has been implemented. I do handle throttle in my driver, but it has been
implemented as a part of work-around for the deficiencies of the old tty
buffering. I seriously doubt I'd realize it's a must to honour throttle
should I start to write the driver today.

-- 
Sergei.

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

end of thread, other threads:[~2006-07-14 10:14 UTC | newest]

Thread overview: 40+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2006-06-30  5:48 [PATCH] Airprime driver improvements to allow full speed EvDO transfers Andy Gay
2006-06-30  7:10 ` Andrew Morton
2006-06-30  8:52   ` Pete Zaitcev
2006-06-30 16:59     ` Andy Gay
2006-06-30 10:51   ` Sergei Organov
2006-06-30 12:13     ` [linux-usb-devel] " Alan Cox
2006-06-30 12:02       ` Arjan van de Ven
2006-06-30 13:34         ` Alan Cox
2006-06-30 16:35   ` Andy Gay
2006-07-07 17:23   ` Sergei Organov
2006-07-07 20:07     ` Alan Cox
2006-07-10 10:36       ` Sergei Organov
2006-07-10 11:10         ` Alan Cox
2006-07-10 15:54           ` Sergei Organov
2006-07-10 17:31             ` Alan Cox
2006-07-10 17:24               ` Sergei Organov
2006-07-13 14:17               ` Sergei Organov
2006-07-13 15:40                 ` Alan Cox
2006-07-13 18:20                   ` Sergei Organov
2006-07-13 19:08                     ` Greg KH
2006-07-14 10:13                       ` Sergei Organov
2006-06-30 20:04 ` Roland Dreier
2006-06-30 20:13   ` Andy Gay
2006-07-02 18:48 ` Roland Dreier
2006-07-02 20:29   ` Andy Gay
2006-07-02 20:47     ` Roland Dreier
2006-07-03  7:00     ` Jeremy Fitzhardinge
2006-07-03 14:21       ` Andy Gay
2006-07-03 16:28         ` Jeremy Fitzhardinge
2006-07-03 17:00           ` Andy Gay
2006-07-03 17:00     ` Greg KH
2006-07-03 17:55       ` Andy Gay
2006-07-03 18:08         ` Jeremy Fitzhardinge
2006-07-03 18:16         ` Greg KH
2006-07-03 22:43           ` Andy Gay
2006-07-03 15:43 ` [linux-usb-devel] " Ken Brush
2006-07-03 16:19   ` Andy Gay
2006-07-11 18:31 ` Sergei Organov
2006-07-11 18:55   ` Andy Gay
2006-07-12  9:20     ` Sergei Organov

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.