USB: serial: sierra driver write path improvements
authorElina Pasheva <epasheva@sierrawireless.com>
Wed, 29 Apr 2009 17:26:46 +0000 (10:26 -0700)
committerGreg Kroah-Hartman <gregkh@suse.de>
Tue, 16 Jun 2009 04:44:45 +0000 (21:44 -0700)
- Updated Copyright notice with new authors names
 - Version number set to 1.3.6
 - Added a MAX_TRANSFER constant following Greg Kroah-Hartman's
   recommended setting of PAGE_SIZE-512 for USB transfer buffers and
   modified accordingly sierra_write() function.

Signed-off-by: Elina Pasheva <epasheva@sierrawireless.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
drivers/usb/serial/sierra.c

index f75688416b653e78144ef3b1a2c4a5008fcda6e5..27f41f95aefbaab7ec3eaf13d49e92dd0b11cb83 100644 (file)
@@ -1,7 +1,10 @@
 /*
   USB Driver for Sierra Wireless
 
-  Copyright (C) 2006, 2007, 2008  Kevin Lloyd <klloyd@sierrawireless.com>
+  Copyright (C) 2006, 2007, 2008  Kevin Lloyd <klloyd@sierrawireless.com>,
+
+  Copyright (C) 2008, 2009  Elina Pasheva, Matthew Safar, Rory Filer
+                       <linux@sierrawireless.com>
 
   IMPORTANT DISCLAIMER: This driver is not commercially supported by
   Sierra Wireless. Use at your own risk.
@@ -14,8 +17,8 @@
   Whom based his on the Keyspan driver by Hugh Blemings <hugh@blemings.org>
 */
 
-#define DRIVER_VERSION "v.1.3.5"
-#define DRIVER_AUTHOR "Kevin Lloyd <klloyd@sierrawireless.com>"
+#define DRIVER_VERSION "v.1.3.6"
+#define DRIVER_AUTHOR "Kevin Lloyd, Elina Pasheva, Matthew Safar, Rory Filer"
 #define DRIVER_DESC "USB Driver for Sierra Wireless USB modems"
 
 #include <linux/kernel.h>
 #define N_OUT_URB      64
 #define IN_BUFLEN      4096
 
+#define MAX_TRANSFER           (PAGE_SIZE - 512)
+/* MAX_TRANSFER is chosen so that the VM is not stressed by
+   allocations > PAGE_SIZE and the number of packets in a page
+   is an integer 512 is the largest possible packet on EHCI */
+
 static int debug;
 static int nmea;
 
@@ -419,50 +427,58 @@ static int sierra_write(struct tty_struct *tty, struct usb_serial_port *port,
        unsigned long flags;
        unsigned char *buffer;
        struct urb *urb;
-       int status;
+       size_t writesize = min((size_t)count, (size_t)MAX_TRANSFER);
+       int retval = 0;
+
+       /* verify that we actually have some data to write */
+       if (count == 0)
+               return 0;
 
        portdata = usb_get_serial_port_data(port);
 
-       dev_dbg(&port->dev, "%s: write (%d chars)\n", __func__, count);
+       dev_dbg(&port->dev, "%s: write (%d bytes)\n", __func__, writesize);
 
        spin_lock_irqsave(&portdata->lock, flags);
+       dev_dbg(&port->dev, "%s - outstanding_urbs: %d\n", __func__,
+               portdata->outstanding_urbs);
        if (portdata->outstanding_urbs > N_OUT_URB) {
                spin_unlock_irqrestore(&portdata->lock, flags);
                dev_dbg(&port->dev, "%s - write limit hit\n", __func__);
                return 0;
        }
        portdata->outstanding_urbs++;
+       dev_dbg(&port->dev, "%s - 1, outstanding_urbs: %d\n", __func__,
+               portdata->outstanding_urbs);
        spin_unlock_irqrestore(&portdata->lock, flags);
 
-       buffer = kmalloc(count, GFP_ATOMIC);
+       buffer = kmalloc(writesize, GFP_ATOMIC);
        if (!buffer) {
                dev_err(&port->dev, "out of memory\n");
-               count = -ENOMEM;
+               retval = -ENOMEM;
                goto error_no_buffer;
        }
 
        urb = usb_alloc_urb(0, GFP_ATOMIC);
        if (!urb) {
                dev_err(&port->dev, "no more free urbs\n");
-               count = -ENOMEM;
+               retval = -ENOMEM;
                goto error_no_urb;
        }
 
-       memcpy(buffer, buf, count);
+       memcpy(buffer, buf, writesize);
 
-       usb_serial_debug_data(debug, &port->dev, __func__, count, buffer);
+       usb_serial_debug_data(debug, &port->dev, __func__, writesize, buffer);
 
        usb_fill_bulk_urb(urb, serial->dev,
                          usb_sndbulkpipe(serial->dev,
                                          port->bulk_out_endpointAddress),
-                         buffer, count, sierra_outdat_callback, port);
+                         buffer, writesize, sierra_outdat_callback, port);
 
        /* send it down the pipe */
-       status = usb_submit_urb(urb, GFP_ATOMIC);
-       if (status) {
+       retval = usb_submit_urb(urb, GFP_ATOMIC);
+       if (retval) {
                dev_err(&port->dev, "%s - usb_submit_urb(write bulk) failed "
-                       "with status = %d\n", __func__, status);
-               count = status;
+                       "with status = %d\n", __func__, retval);
                goto error;
        }
 
@@ -470,7 +486,7 @@ static int sierra_write(struct tty_struct *tty, struct usb_serial_port *port,
         * really free it when it is finished with it */
        usb_free_urb(urb);
 
-       return count;
+       return writesize;
 error:
        usb_free_urb(urb);
 error_no_urb:
@@ -478,8 +494,10 @@ error_no_urb:
 error_no_buffer:
        spin_lock_irqsave(&portdata->lock, flags);
        --portdata->outstanding_urbs;
+       dev_dbg(&port->dev, "%s - 2. outstanding_urbs: %d\n", __func__,
+               portdata->outstanding_urbs);
        spin_unlock_irqrestore(&portdata->lock, flags);
-       return count;
+       return retval;
 }
 
 static void sierra_indat_callback(struct urb *urb)